loading...

Build a Responsive Website using Svelte in 30 minutes.

karkranikhil profile image Nikhil karkra ・10 min read

In This tutorial, we will build a beautiful responsive app in 30 Minutes using svelte.
Let's look at the design we are going to build.
Alt Text

I have divided the page into 7 components and these 7 components are the child of App component as shown below.

Alt Text

Let's setup our project called digital_agency_using_svelte. Go to terminal, you can instantly create a new project by running the following command.

npx degit sveltejs/template digital_agency_using_svelte
cd digital_agency_using_svelte
npm install

Adding Bootstrap and fontawesome to the project

For this demo, i am using the following CDN and adding these files to the index.html that is available under the public folder.

<!--Bootstrap.css-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"crossorigin="anonymous">

<!--fontawesome.js-->
<script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script>

<!--Slim.js-->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>

<!--bootstrap.js-->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
        crossorigin="anonymous"></script>

Adding global styles to the project.

You can add the following css to the global.css that is available under the public folder.

/**public/global.css**/
:root {
  --gradient: linear-gradient(90deg, #0072ff 0%, #00d4ff 100%);
  --light: #fff;
  --grey: #f8f9fa;
}

html,
body {
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica, sans-serif;
  scroll-behavior: smooth;
}
.main-bgcolor {
  background-image: var(--gradient);
}
.light-color {
  color: var(--light) !important;
}
.grey-bgcolor {
  background: var(--grey);
}
.company_brand {
  font-size: x-large;
  font-family: cursive;
}

.section {
  padding: 50px 0;
}

.section-body {
  padding: 20px 0;
}



Adding static Data to the project.

I have created a JSON of static data that is used in the project. Create a Data folder inside the src folder and under the Data folder create a file data.js. Add the following static data to it.

/**src/Data/data.js**/
const HEADER = "Nixalar";

const NAVBAR_DATA = [
  { id: 1, url: "/", label: "Home" },
  { id: 2, url: "#services", label: "Services" },
  { id: 3, url: "#about-us", label: "About us" },
  { id: 4, url: "#testimonials", label: "Testimonials" },
  { id: 5, url: "#footer", label: "Contacts" }
];
const BANNER_DATA = {
  HEADING: "Go digital with nixalar",
  DECRIPTION:
    "Nixalar can help you skyrocket the ROI of your marketing campaign without having to spend tons of money or time to assemble an in-house team.",
  TUTORIAL_URL:
    "https://www.thinkwithgoogle.com/intl/en-gb/marketing-resources/programmatic/google-digital-academy/",
  WATCH_TUTORIAL: "Watch Tutorials"
};
const SERVICE_DATA = {
  HEADING: "Our Services",
  ALL_SERVICES: "All Services",
  SERVICE_LIST: [
    {
      LABEL: "Search Engine Optimisation",
      DESCRIPTION:
        "To customise the content, technical functionality and scope of your website so that your pages show for a specific set of keyword at the top of a search engine list. In the end, the goal is to attract traffic to your website when they are searching for goods, services or business-related information.",
      URL: "images/service1.png"
    },
    {
      LABEL: "Content Marketing Strategy",
      DESCRIPTION:
        "It is tough but well worth the effort to create clever material that is not promotional in nature, but rather educates and inspires. It lets them see you as a reliable source of information by delivering content that is meaningful to your audience.",
      URL: "images/service2.png"
    },
    {
      LABEL: "Develop Social Media Strategy",
      DESCRIPTION:
        "Many People rely on social networks to discover, research, and educate themselves about a brand before engaging with that organization. The more your audience wants to engage with your content, the more likely it is that they will want to share it.",
      URL: "images/service3.png"
    }
  ]
};

const ABOUT_DATA = {
  HEADING: "Why choose us?",
  TITLE: "Why we're different",
  IMAGE_URL: "images/network.png",
  WHY_CHOOSE_US_LIST: [
    "We provides Cost-Effective Digital Marketing than Others.",
    "High customer statisfaction and experience.",
    "Marketing efficiency and quick time to value.",
    "Clear & transparent fee structure.",
    "We provides Marketing automation which is an integral platform that ties all of your digital marketing together.",
    "A strong desire to establish long lasting business partnerships.",
    "Provide digital marketing to mobile consumer.",
    "We provides wide range to services in reasonable prices"
  ]
};
const TESTIMONIAL_DATA = {
  HEADING: "What clients say?",
  TESTIMONIAL_LIST: [
    {
      DESCRIPTION:
        "Nixalar has made a huge difference to our business with his good work and knowledge of SEO and business to business marketing techniques. Our search engine rankings are better than ever and we are getting more people contacting us thanks to Jomer’s knowledge and hard work.",
      IMAGE_URL: "images/user1.jpg",
      NAME: "Julia hawkins",
      DESIGNATION: "Co-founder at ABC"
    },
    {
      DESCRIPTION:
        "Nixalar and his team have provided us with a comprehensive, fast and well planned digital marketing strategy that has yielded great results in terms of content, SEO, Social Media. His team are a pleasure to work with, as well as being fast to respond and adapt to the needs of your brand.",
      IMAGE_URL: "images/user2.jpg",
      NAME: "John Smith",
      DESIGNATION: "Co-founder at xyz"
    }
  ]
};

const SOCIAL_DATA = {
  HEADING: "Find us on social media",
  IMAGES_LIST: [
    "images/facebook-icon.png",
    "images/instagram-icon.png",
    "images/whatsapp-icon.png",
    "images/twitter-icon.png",
    "images/linkedin-icon.png",
    "images/snapchat-icon.png"
  ]
};

const FOOTER_DATA = {
  DESCRIPTION:
    "We are typically focused on result-based maketing in the digital world. Also, we evaluate your brand’s needs and develop a powerful strategy that maximizes profits.",
  CONTACT_DETAILS: {
    HEADING: "Contact us",
    ADDRESS: "La trobe street docklands, Melbourne",
    MOBILE: "+1 61234567890",
    EMAIL: "nixalar@gmail.com"
  },
  SUBSCRIBE_NEWSLETTER: "Subscribe newsletter",
  SUBSCRIBE: "Subscribe"
};

const MOCK_DATA = {
  HEADER,
  NAVBAR_DATA,
  BANNER_DATA,
  SERVICE_DATA,
  ABOUT_DATA,
  TESTIMONIAL_DATA,
  SOCIAL_DATA,
  FOOTER_DATA
};
export default MOCK_DATA;

Adding Images to the project.

In this project, we have used many images. so, first create an images folder under the public folder and download the images from the following Link and add the images to the images folder Images Link

*Before creating the components create a Components folder inside the src folder. *

Navbar component

Create a folder Navbar inside the components folder and within that create a file Navbar.svelte. Add the following code to it.

<!--src/Components/Navbar/Navbar.svelte-->

<script>
  export let navlists = [];
  export let header;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="nav-bar">
  <nav class="navbar main-bgcolor navbar-expand-md navbar-dark">
    <a class="navbar-brand company_brand" href="/">
      {header}
    </a>
    <button
      class="navbar-toggler"
      type="button"
      data-toggle="collapse"
      data-target="#navbarNav"
      aria-controls="navbarNav"
      aria-expanded="false"
      aria-label="Toggle navigation">
      <span class="navbar-toggler-icon" />
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav ml-auto">
        {#each navlists as list}
          <li class="nav-item">
            <a class="nav-link light-color" href={list.url}>{list.label}</a>
          </li>
        {/each}
      </ul>
    </div>
  </nav>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
  #nav-bar {
    position: sticky;
    top: 0;
    z-index: 10;
  }

  .navbar {
    padding: 0 20px !important;
  }

  .navbar-nav li {
    padding: 0 0 0 20px;
  }

  .navbar-nav li a {
    font-weight: 600;
    text-transform: uppercase;
    float: right;
    text-align: left;
  }
</style>

In Navbar component we are using the navlists and header that will be pass through the parent component(App.svelte).

Banner component

Create a folder Banner inside the components folder and within that create a file Banner.svelte. Add the following code to it.

<!--src/Components/Banner/Banner.svelte-->

<script>
  export let bannerData = {};
  const { HEADING, DECRIPTION, TUTORIAL_URL, WATCH_TUTORIAL } = bannerData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section class="main-bgcolor light-color" id="banner">
  <div class="container">
    <div class="row">
      <div class="col-md-6">
        <h1>{HEADING}</h1>
        <p>{DECRIPTION}</p>
        <a href={TUTORIAL_URL} target="_blank" class="light-color">
          <i class="far fa-play-circle fa-2x watch-btn" />
          {WATCH_TUTORIAL}
        </a>
      </div>
      <div class="col-md-6">
        <img src="images/home.png" alt="" class="img-fluid" />
      </div>
    </div>
  </div>
  <img src="images/wave1.png" alt="" class="wave-img" />
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
  section {
    padding-top: 5%;
  }

  h1 {
    font-size: 40px;
    font-weight: 600;
    margin-top: 100px;
    text-transform: uppercase;
  }

  .watch-btn {
    margin: auto 20px;
    position: relative;
    top: 8px;
  }

  section a {
    text-decoration: none;
  }

  .wave-img {
    width: 100%;
    height: auto;
  }
</style>

In Banner component we are using the bannerData that will be pass through the parent component(App.svelte).

Services component

Create a folder Services inside the components folder and within that create a file Services.svelte. Add the following code to it.

<!--src/Components/Services/Services.svelte-->

<script>
  export let serviceData = {};
  const { HEADING, ALL_SERVICES, SERVICE_LIST } = serviceData;
</script>

<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="services" class="section">
  <div class="container text-center">
    <h2 class="title">{HEADING}</h2>
    <div class="row section-body">
      {#each SERVICE_LIST as list}
        <div class="col-md-4 service">
          <img src={list.URL} alt={list.LABEL} class="service-img" />
          <h4>{list.LABEL}</h4>
          <p>{list.DESCRIPTION}</p>
        </div>
      {/each}
    </div>
    <buttom class="btn btn-primary round-border main-bgcolor">
      {ALL_SERVICES}
    </buttom>
  </div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
  .service-img {
    width: 200px;
    height: 200px;
    margin-top: 20px;
  }

  .service h4 {
    padding: 5px;
    margin-top: 25px;
    text-transform: uppercase;
  }

  .title {
    text-transform: uppercase;
  }

  .title::before {
    content: "";
    background: linear-gradient(90deg, #0072ff 0%, #00d4ff 100%);
    height: 5px;
    width: 200px;
    margin-left: auto;
    margin-right: auto;
    display: block;
    transform: translateY(60px);
  }

  .title::after {
    content: "";
    background: linear-gradient(90deg, #0072ff 0%, #00d4ff 100%);
    height: 10px;
    width: 50px;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 40px;
    display: block;
    transform: translateY(14px);
  }

  section .btn-primary {
    box-shadow: none;
    padding: 8px 25px;
    border: none;
  }
</style>

In Services component we are using the serviceData that will be pass through the parent component(App.svelte).

About component

Create a folder About inside the components folder and within that create a file About.svelte. Add the following code to it.

<!--src/Components/About/About.svelte-->

<script>
  export let aboutData = {};
  const { HEADING, TITLE, IMAGE_URL, WHY_CHOOSE_US_LIST } = aboutData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="about-us" class="section grey-bgcolor">
  <div class="container">
    <h2 class="title text-center">{HEADING}</h2>
    <div class="row section-body">
      <div class="col-md-6">
        <h3 class="about-title">{TITLE}</h3>
        <ul>
          {#each WHY_CHOOSE_US_LIST as list}
            <li>{list}</li>
          {/each}
        </ul>
      </div>
      <div class="col-md-6">
        <img src={IMAGE_URL} alt="" class="img-fluid" />
      </div>
    </div>
  </div>
</section>

<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
  .about-title {
    margin-top: 8%;
    margin-bottom: 20px;
  }

  section ul li {
    margin: 10px 0;
  }

  section ul {
    padding-left: 23px;
  }
</style>

In About component we are using the aboutData that will be pass through the parent component(App.svelte).

Testimonials component

Create a folder Testimonials inside the components folder and within that create a file Testimonials.svelte. Add the following code to it.

<!--src/Components/Testimonials/Testimonials.svelte-->

<script>
  export let testimonialData = {};
  const { HEADING, TESTIMONIAL_LIST } = testimonialData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->

<section id="testimonials" class="section">
  <div class="container">
    <h2 class="title text-center">{HEADING}</h2>
    <div class="row offset-1 section-body">
      {#each TESTIMONIAL_LIST as list}
        <div class="col-md-5 testimonial">
          <p>{list.DESCRIPTION}</p>
          <img src={list.IMAGE_URL} alt="" />
          <p class="user-details">
            <b>{list.NAME}</b>
            <br />
            {list.DESIGNATION}
          </p>
        </div>
      {/each}
    </div>
  </div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
  .testimonial {
    border-left: 4px solid #0072ff80;
    margin-top: 10px;
    margin-bottom: 10px;
  }

  .testimonial img {
    height: 60px;
    width: 60px;
    border-radius: 50%;
    margin: 0 10px;
  }

  .user-details {
    display: inline-block;
    font-size: 12px;
  }
</style>

In Testimonials component we are using the testimonialData that will be pass through the parent component(App.svelte).

Social component

Create a folder Social inside the components folder and within that create a file Social.svelte. Add the following code to it.

<!--src/Components/Social/Social.svelte-->

<script>
  export let socialData = {};
  const { IMAGES_LIST, HEADING } = socialData;
</script>
<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section id="social-media" class="section grey-bgcolor">
  <div class="container text-center">
    <h2 class="title text-center">{HEADING}</h2>
    <div class="social-icons section-body">
      {#each IMAGES_LIST as list}
        <a
          href="https://www.linkedin.com/in/nikhil-karkra-73a15319/"
          target="_blank">
          <img src={list} alt="Social media {list}" />
        </a>
      {/each}
    </div>
  </div>
</section>
<!------------------------------------------->
<!----------------STYLE----------------------->
<!------------------------------------------->
<style>
  .social-icons img {
    width: 75px;
    transition: 0.5s;
  }
  .social-icons a:hover img {
    transform: translateY(-10px);
  }
  a:hover {
    text-decoration: none;
  }
</style>

In Social component we are using the socialData that will be pass through the parent component(App.svelte).

Footer component

Create a folder Footer inside the components folder and within that create a file Footer.svelte. Add the following code to it.

<!--src/Components/Footer/Footer.svelte-->

<script>
  export let footerData = {};
  export let header = "";
  const {
    DESCRIPTION,
    CONTACT_DETAILS,
    SUBSCRIBE_NEWSLETTER,
    SUBSCRIBE
  } = footerData;
  const { HEADING, ADDRESS, MOBILE, EMAIL } = CONTACT_DETAILS;
</script>

<!------------------------------------------->
<!----------------MARKUP----------------------->
<!------------------------------------------->
<section class="main-bgcolor light-color" id="footer">
  <img src="images/wave2.png" alt="" class="wave-img" />
  <div class="container">
    <div class="row section-body">
      <div class="col-md-4 footer-box">
        <div class="company_brand">{header}</div>
        <p>{DESCRIPTION}</p>
      </div>
      <div class="col-md-4 footer-box">
        <p class="footer-title">{HEADING}</p>
        <p>
          <i class="fas fa-map-marker-alt" />
          {ADDRESS}
        </p>
        <p>
          <i class="fas fa-phone" />
          {MOBILE}
        </p>
        <p>
          <i class="fas fa-envelope" />
          {EMAIL}
        </p>
      </div>
      <div class="col-md-4 footer-box">
        <p class="footer-title">{SUBSCRIBE_NEWSLETTER}</p>
        <input
          type="email"
          class="form-control round-border"
          placeholder="Your Email" />
        <button type="button" class="btn btn-outline-light round-border">
          {SUBSCRIBE}
        </button>
      </div>
    </div>
  </div>
</section>
<!------------------------------------------->
<!----------------Style----------------------->
<!------------------------------------------->
<style>
  .footer-title {
    font-weight: bold;
    text-transform: uppercase;
  }

  .footer-box button {
    margin-top: 30px;
  }

  .round-border {
    border-radius: 20px !important;
  }
  .wave-img {
    width: 100%;
    height: auto;
  }
</style>

In Footer component, we are using the footerData and header that will be pass through the parent component(App.svelte).

Adding Child components to Parent (App.svelte)

Till now we are ready with our Child components. Let's add them to App.Svelte.
Go to App.Svelte replace the existing code with the below code.

<!--src/App.svelte-->
<script>
  import Navbar from "./Components/Navbar/Navbar.svelte";
  import Banner from "./Components/Banner/Banner.svelte";
  import Services from "./Components/Services/Services.svelte";
  import About from "./Components/About/About.svelte";
  import Testimonials from "./Components/Testimonials/Testimonials.svelte";
  import Social from "./Components/Social/Social.svelte";
  import Footer from "./Components/Footer/Footer.svelte";
  import DATA from "./Data/data";
</script>

<!-- Navbar -->
<Navbar navlists={DATA.NAVBAR_DATA} header={DATA.HEADER} />
<!-- Banner -->
<Banner bannerData={DATA.BANNER_DATA} } />
<!-- Services -->
<Services serviceData={DATA.SERVICE_DATA} />
<!-- About -->
<About aboutData={DATA.ABOUT_DATA} />
<!-- Testimonials -->
<Testimonials testimonialData={DATA.TESTIMONIAL_DATA} />
<!-- Social Media -->
<Social socialData={DATA.SOCIAL_DATA} />
<!-- Footer -->
<Footer footerData={DATA.FOOTER_DATA} header={DATA.HEADER} />

If you look at the code above. We are passing the props to the each component wherever it's required. We are ideally passing the static data that we created in Data/data.js.

Run the project

Now our project is ready. let's run the project using the following command.

npm run dev

Go to http://localhost:5000/. You will see the following output
Alt Text

Code and reference

I have deployed it to now https://nixalar-digital-agency.now.sh/

Github
https://github.com/karkranikhil/Digital-Agency-using-svelte

Discussion

pic
Editor guide
Collapse
dealloc profile image
Wannes Gennar

This is not directly related to Svelte; but I'm seeing a trend where websites like this with almost purely static content are written in frontend frameworks like Svelte, Vue, React or Angular while they don't need the overhead.
Websites like this should just be plain HTML files, some CSS sprinkled in and no Javascript.

Collapse
theague profile image
Kody James Ague

Would love to know, time taken to build in HTML/css only and what the mobile score would be on a page like that? 👍🏻👍🏻

Collapse
karkranikhil profile image
Nikhil karkra Author

I agree with you this demo is more of HTML and CSS but Svelte is not a framework or library it's a Compiler. So at the end everything is plain JS.

Collapse
mattwaler profile image
Matt Waler

This page is definitely not Svelte's main use case. This page should be static HTML/CSS/JS so it can be indexed properly by all bots. A simple templating language like Nunjucks/Pug and some SCSS would yield much better SEO, page speed, and page file size.

Collapse
karkranikhil profile image
Nikhil karkra Author

I agree Svelte actual use case comes when we have Single page application where i can reuse my components. But with the same demo i can achieve better page speed and SEO. Svelte is a compiler; it compiles components into JavaScript. SO bundle size is very less compare to other lib and frameworks

Collapse
peterthompsonnz profile image
Peter Thompson

Thank you for sharing your tutorial. The finished product looks great. I analyzed the completed page, using the link you provided, with Google Pagespeed and found that the mobile score was only 76, and that some easy optimizations could be made.

Collapse
karkranikhil profile image
Nikhil karkra Author

Yeah we can improve this..once I LL get time I LL do it.

Collapse
wearahelmet profile image
Vern Martin

Thank you for this. I'm just getting started with Svelte, and while I see comments saying this "should" be done in pure HTML and CSS, I needed to see how this much could be done in Svelte and how Svelte components might be organized -- and above all how to add bootstrap!

Collapse
karkranikhil profile image
Nikhil karkra Author

github.com/bestguy/sveltestrap

You can use sveltestrap. I have used the CDN of Bootstrap. You can download the bootstrap and place it under public folder and give the same path in index.html

Collapse
dbshanks profile image
Derek Shanks

Fantastic. This is what I love about Svelte and you showed a great representation of how to use Svelte and its practicality for simpler but truly dynamic and re-usable code.

Svelte truly is a designers toolset and absolutely capable of very complex application logic.

Great job!!

Collapse
mjosborne1 profile image
Michael Osborne

If you don't want to load the whole CSS framework, you can load it in with node-sass in your package bundler and use a styles.scss file. Example of that for Bulma is:

// Import only what you need from Bulma
@import "../node_modules/bulma/sass/utilities/_all.sass";
@import "../node_modules/bulma/sass/base/_all.sass";
@import "../node_modules/bulma/sass/components/_all.sass";
@import "../node_modules/bulma/sass/elements/_all.sass";
@import "../node_modules/bulma/sass/form/_all.sass";
@import "../node_modules/bulma/sass/grid/_all.sass";
@import "../node_modules/bulma/sass/layout/_all.sass";

Collapse
igorfilippov3 profile image
Igor Filippov

If your goal is to slow down browser rendering speed - yes, it is great idea. Instead of loading and rendering static html page browser should load index.html, than load, parse and execute js bundle, and at the end the user will see some content.

It will be much better to apply your vision with sapper and data in json format

Collapse
mjosborne1 profile image
Michael Osborne

I have a question on style for you.
If you wanted to split the 'About' page out onto it's own page, would the route be to a static file in PUBLIC (e.g. about.html) or to another svelte component and how could the Nav bar be reused in that case?

Collapse
sonyarianto profile image
Sony AK

wow this is nice and practical, love it.

Collapse
gndx profile image