Tag: Svelte

Lazy Loading Images in Svelte

One easy way to improve the speed of a website is to only download images only when they’re needed, which would be when they enter the viewport. This “lazy loading” technique has been around a while and there are lots of great tutorials on how to implement it.

But even with all the resources out there, implementing lazy loading can look different depending on the project you’re working in or the framework you’re using. In this article, I’ll use the Intersection Observer API alongside the onLoad event to lazy load images with the Svelte JavaScript framework.

Check out Tristram Tolliday’s introduction to Svelte if you’re new to the framework.

Let’s work with a real-life example

I put this approach together while testing the speed on a Svelte and Sapper application I work on, Shop Ireland. One of our goals is to make the thing as fast as we possible can. We hit a point where the homepage was taking a performance hit because the browser was downloading a bunch of images that weren’t even on the screen, so naturally, we turned to lazy loading them instead.

Svelte is already pretty darn fast because all of the code is compiled in advance. But once we tossed in lazy loading for images, things really started speeding up.

This is what we’re going to work on tofgether. Feel free to grab the final code for this demo from GitHub and read along for an explanation of how it works.

This is where we’ll end up by the end:

Let’s quickly start up Svelte

You might already have a Svelte app you’d like to use, but if not, let’s start a new Svelte project and work on it locally. From the command line:

npx degit sveltejs/template my-svelte-project cd my-svelte-project npm install npm run dev

You should now have a beginner app running on http://localhost:5000.

Adding the components folder

The initial Svelte demo has an App.svelte file but no components just yet. Let’s set up the components we need for this demo. There is no components  folder, so let’s create one in the src folder. Inside that folder, create an Image folder — this will hold our components for this demo.

We’re going to have our components do two things. First, they will check when an image enters the viewport. Then, when an image does enter, the components will wait until the image file has loaded before showing it.

The first component will be an <IntersectionObserver> that wraps around the second component, an <ImageLoader>. What I like about this setup is that it allows each component to be focused on doing one thing instead of trying to pack a bunch of operations in a single component.

Let’s start with the <IntersectionObserver> component.

Observing the intersection

Our first component is going to be a working implementation of the Intersection Observer API. The Intersection Observer is a pretty complex thing but the gist of it is that it watches a child element and informs us when it enters the bounding box of its parent. Hence images: they can be children of some parent element and we can get a heads up when they scroll into view.

While it’s definitely a great idea to get acquainted with the ins and outs of the Intersection Observer API — and Travis Almand has an excellent write-up of it — we’re going to make use of a handy Svelte component that Rich Harris put together for svelte.dev.

We’ll set this up  first before digging into what exactly it does. Create a new IntersectionObserver.svelte file and drop it into the src/components/Image folder. This is where we’ll define the component with the following code:

<script>   import { onMount } from 'svelte'; 
   export let once = false;   export let top = 0;   export let bottom = 0;   export let left = 0;   export let right = 0; 
   let intersecting = false;   let container; 
   onMount(() => {     if (typeof IntersectionObserver !== 'undefined') {       const rootMargin = `$  {bottom}px $  {left}px $  {top}px $  {right}px`; 
       const observer = new IntersectionObserver(entries => {         intersecting = entries[0].isIntersecting;         if (intersecting && once) {           observer.unobserve(container);         }       }, {         rootMargin       }); 
       observer.observe(container);       return () => observer.unobserve(container);     } 
     function handler() {       const bcr = container.getBoundingClientRect(); 
       intersecting = (         (bcr.bottom + bottom) > 0 &&         (bcr.right + right) > 0 &&         (bcr.top - top) < window.innerHeight &&         (bcr.left - left) < window.innerWidth       ); 
       if (intersecting && once) {         window.removeEventListener('scroll', handler);       }     } 
     window.addEventListener('scroll', handler);     return () => window.removeEventListener('scroll', handler);   }); </script> 
 <style>   div {     width: 100%;     height: 100%;   } </style> 
 <div bind:this={container}>   <slot {intersecting}></slot> </div>

We can use this component as a wrapper around other components, and it will determine for us whether the wrapped component is intersecting with the viewport.

If you’re familiar with the structure of Svelte components, you’ll see it follows a pattern that starts with scripts, goes into styles, then ends with markup. It sets some options that we can pass in, including a once property, along with numeric values for the top, right, bottom and left distances from the edge of the screen that define the point where the intersection begins.

We’ll ignore the distances but instead make use of the once property. This will ensure the images only load once, as they enter the viewport.

The main logic of the component is within the onMount section. This sets up our observer, which is used to check our element to determine if it’s “intersecting” with the visible area of the screen. It also attaches a scroll event to check whether the element is visible as we scroll, and then it’ll remove this listener if we’ve determined that it is viable and that once is true.

Loading the images

Let’s use our <IntersectionObserver> component to conditionally load images by wrapping it around an <ImageLoader> component. Again, this is the component that receives a notification from the <IntersectionOberserver> so it knows it’s time to load an image.

That means we’ll need a new component file in components/Image. Let’s call it ImageLoader.svelte. Here’s the code we want in it:

<script>   export let src   export let alt 
   import IntersectionObserver from './IntersectionObserver.svelte'   import Image from './Image.svelte'    </script> 
 <IntersectionObserver once={true} let:intersecting={intersecting}>   {#if intersecting}     <Image {alt} {src} />   {/if} </IntersectionObserver>

This component takes some image-related props — src and alt — that we will use to create the actual markup for an image. Notice that we’re importing two components in the scripts section, including the <IntersectionObserver> we just created and another one called <Image> that we haven’t created yet, but will get to in a moment.

The <IntersectionObserver> is put to work by acting as a wrapping around the soon-to-be-created <Image> component. Check out those properties on it.  We are setting once to true, so the image only loads the first time we see it.

Then we make use of Svelte’s slot props. What are those? Let’s cover that next.

Slotting property values

Wrapping component, like our <IntersectionObserver> are handy for passing props to the children it contains. Svelte gives us something called slot props to make that happen.

In our <IntersectionObserver> component you may have noticed this line:

<slot {intersecting}></slot>

This is passing the intersecting prop into whatever component we give it. In this case, our <ImageLoader> component receives the prop when it uses the wrapper. We access the prop using let:intersecting={intersecting} like so:

<IntersectionObserver once={true} let:intersecting={intersecting}>

We can then use the intersecting value to determine when it’s time to load an <Image> component. In this case, we’re using an if condition to check for when it’s go time:

<IntersectionObserver once={true} let:intersecting={intersecting}>   {#if intersecting}     <Image {alt} {src} />   {/if} </IntersectionObserver> 

If the intersection is happening, the <Image> is loaded and receives the alt and src props. You can learn a bit more about slot props in this Svelte tutorial.

We now have the code in place to show an <Image> component when it is scrolled onto the screen. Let’s finally get to building the component.

Showing images on load

Yep, you guessed it: let’s add an Image.svelte file to the components/Image folder for our <Image> component. This is the component that receives our alt and src props and sets them on an <img> element.

Here’s the component code:

<script>   export let src   export let alt 
   import { onMount } from 'svelte' 
   let loaded = false   let thisImage 
   onMount(() => {     thisImage.onload = () => {       loaded = true     }   })  
 </script> 
 <style>   img {     height: 200px;     opacity: 0;     transition: opacity 1200ms ease-out;   }   img.loaded {     opacity: 1;   } </style> 
 <img {src} {alt} class:loaded bind:this={thisImage} />

Right off the bat, we’re receiving the alt and src props before defining two new variables: loaded to store whether the image has loaded or not, and thisImage to store a reference to the img DOM element itself.

We’re also using a helpful Svelte method called onMount. This gives us a way to call functions once a component has been rendered in the DOM. In this case, we’re set a callback for thisImage.onload. In plain English, that means it’s executed when the image has finished loading, and will set the loaded variable to a true value.

We’ll use CSS to reveal the image and fade it into view. Let’s give set an opacity: 0 on images so they are initially invisible, though technically on the page. Then, as they intersect the viewport and the <ImageLoader> grants permission to load the image, we’ll set the image to full opacity. We can make it a smooth transition by setting the transition property on image. The demo sets the transition time to 1200ms but you can speed it up or slow it down as needed.

That leads us to the very last line of the file, which is the markup for an <img> element.

<img {src} {alt} class:loaded bind:this={thisImage} />

This uses class:loaded to conditionally apply a .loaded class if the loaded variable is true. It also uses the bind:this method to associate this DOM element with the thisImage variable.

Let’s hook it all up!

Alright, it’s time to actually use our component. Crack open the App.svelte file and drop in the following code to import our component and use it:

<script>   import ImageLoader from './components/Image/ImageLoader.svelte'; </script> 
 <ImageLoader src="OUR_IMAGE_URL" alt="Our image"></ImageLoader>

Here’s the demo once again:

And remember that you’re welcome to download the complete code for this demo on GitHub. If you’d like to see this working on a production site, check out my Shop Ireland project. Lazy loading is used on the homepage, category pages and search pages to help speed things up. I hope you find it useful for your own Svelte projects!


The post Lazy Loading Images in Svelte appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,

Getting Acquainted With Svelte, the New Framework on the Block

For the last six years, Vue, Angular, and React have run the world of front-end component frameworks. Google and Facebook have their own sponsored frameworks, but they might leave a bitter taste for anyone who advocates for an open and unbiased web. Vue is another popular framework that has multiple sponsors, but isn’t run by a single corporation, which may be attractive to some folks.

There’s another player in the framework space that’s gaining attention and operates very much in the same spirit as Vue as far adopting an open MIT license: Svelte.

Svelte has been covered here on CSS-Tricks before, like Ollie Williams’ excellent overview of how it can be used to write more convenient, component-based CSS. This article is going to zoom out a bit and provide a little more context about Svelt, as well as how it differentiates itself from other frameworks, and how to implement it in your own projects.

What makes Svelte different?

I can confidently say that Svelte has been the easiest JavaScript component library to learn and start putting to use in a productive way.

— Jeff Delaney, from Svelte Realtime Todo List with Firebase

OK, so Svelte is a JavaScript component library. But so is React. And Angular. And Vue. What makes Svelte stand out from the bunch?

Svelte is trying to do a few things that are different from the rest:

  1. All the code is compiled ahead of time.
  2. There is no virtual DOM.
  3. CSS scoping is baked in.

Let’s break those down a bit because they significantly distinguish Svelte from other front-end frameworks.

All the code is compiled ahead of time.

Svelte is a compiler, meaning that the code in Svelte files gets converted from an easier-to-write hybrid language that mixes HTML, JavaScript, and CSS into lower-level optimized JavaScript, HTML, and CSS files.

This is very similar to the way C# gets compiled down to bytecode, or how Typescript compiles down to JavaScript. But where traditional compilers tend to go down to one language, Svelte mixes all three.

This makes writing code a lot more flexible, and benefits the client (web browser) as the computation is done when the application is built, not on every browser when the web app is visited.

There is no Virtual DOM.

A DOM (or Document Object Model) is an interface that defines the logical structure of a webpage. It takes HTML and converts it to a structure that can be manipulated and accessed. Chris has a classic post that thoroughly explains it.

The Virtual DOM extends the concept of a DOM by creating a “second” DOM in memory. Like the DOM, this is manipulated and accessed by traditional frameworks (e.g. Angular, Vue, and React). At build, this second “virtual” DOM gets consolidated with the actual DOM, allowing the UI to render.

And what about the Shadow DOM? Well, the Shadow DOM is technically part of the “real” DOM, just in the shadows. As such it is a great tool for isolating chunks of code that don’t leak into or conflict with other elements on the page — a little bit like (but at the same time almost nothing like) an iframe. The shadow DOM is sorta the crux for most component-based front-end frameworks because they leverage the siloed nature of the Shadow DOM to serve specific code to specific elements.

While that isn’t exactly a key selling point of Svelte, it is possible to work with the Shadow DOM experimentally. The Shadow DOM hasn’t really quite caught on in progressive web practices, which is a shame, and probably due to the confusion between drafts and lack of support from IE and Edge.

So, where am I going with all this? The difference between Svelte and other JavaScript frameworks is the lack of a Virtual DOM. That’s important because it contributes to faster apps — faster than frameworks using a Virtual DOM. Yes, the Virtual DOM can be super fast because it only updates parts of the DOM when needed, but as applications grow, the impact of a duplicate DOM stored in memory can have an overall negative impact on performance.

Svelte takes a different approach and does a lot of these heavy calculations at build time. All that heavy lifting in advance, which allows Svelte to surgically insert changes only where needed.

CSS scoping is baked in.

Svelte has built-in styling, which is essential in other modern frameworks. The different between CSS in Svelte and CSS in other frameworks is that Svelte takes the CSS from each component and spits it out to a separate CSS file on build.

A personal gripe I have with most CSS-in-JS approaches is that it seems like an over-engineered solution. Svelte’s approach keeps things lean, vanilla, and encapsulated — while keeping everything where it should be.

For those who love preprocessors, there are plugins, whether it for Sass, Less or Gulp. But since Svelte is still in its infancy, I would recommend using plain ol’ CSS with a minified CSS framework of your choice so you can utilize Svelte’s handy dandy component scoping. 

You could just as easily keep to your usual styling preferences and completely forgo Svelte’s CSS builder. However, I’d argue that is a massive shame, as Svelte’s solution has been extremely clean and enjoyable, at lease in my experience. But anyone who has to work with IE11 (😬) and even older browsers will know that normalizing styles is a must. This is a good place to stop and check out Ollie’s post because he dives much deeper into Svelte’s styling features and advantages.

How Svelte stacks up to other frameworks

We just looked at what how Svelte has a different approach for compiling, interacting with DOM and writing CSS. You might be wondering: how does Svelte compare to other popular frameworks?

There are plenty of comparisons already out there, but suffice to say that Svelte is pretty darn fast. But speed isn’t the only basis for comparison. Instead, let’s do a side-by-side that looks at a broader overview in a format much loved by the development community: a table!

Svelte Vue React Angular (2+)
What is it Compiler Framework Framework Framework
First Commit Nov. 16, 2016 Jul. 29, 2013 May 24, 2013 Sep. 18, 2014
Backing Open source Multiple Sponsors Facebook Google
Community¹ Small Large Massive Large
Satisfaction2 88% 87% 89% 38%

Svelte is in a strong position considering its late entrance and small community. Developer satisfaction is high, while the big three have been seeing recent declines. The Svelte community is small, but growing, and the code is open source which is a huge plus for the overall web community.

Let’s look at an example of using Svelte

I hope that I have convinced you that Svelte is worth at least a try. If so, let’s fire up the terminal and try a real-world examples of an everyday use case: implementing the Intersection Observer. If you’ve ever run a Lighthouse report, it may have been shouted at you for not using passive scroll events. That may be the most boring sentence I have written in my life, but it’s scores points for performance and isn’t overly complicated to do with the Intersection Observer in Svelte.

Let’s skip all the installation and setup stuff because we can avoid it with REPL, the online editor Svelte uses to demonstrate the framework on its site. The standard “Hello world” boilerplate is in there. Go ahead and download the ZIP file of the app, in the upper-right corner of the screen.

Now, unzip the file and cd into the folder from the terminal and run  npm -i to initialize the project. Once that’s done, do npm run build and you’ll get a copy of your lightweight miniature Svelte “Hello, world!” app.

Now we can get into the actual task of adding the IntersectionObserver.

First, we import the code that has already kindly been written by the Svelte team. It’s in the source code of the svelte.dev git repo (the inner cogs of which make for fascinating reading).

<script>   import { onMount } from 'svelte';   export let once = false;   export let top = 0;   export let bottom = 0;   export let left = 0;   export let right = 0;   let intersecting = false;   let container;    onMount(() => {     if (typeof IntersectionObserver !== 'undefined') {       const rootMargin = `$  {bottom}px $  {left}px $  {top}px $  {right}px`;       const observer = new IntersectionObserver(entries => {         intersecting = entries[0].isIntersecting;         if (intersecting && once) {           observer.unobserve(container);         }         }, {           rootMargin       });         observer.observe(container);         return () => observer.unobserve(container);   }    function handler() {     const bcr = container.getBoundingClientRect();     intersecting = (       (bcr.bottom + bottom) > 0 &&       (bcr.right + right) > 0 &&       (bcr.top - top) < window.innerHeight &&       (bcr.left - left) < window.innerWidth     );     if (intersecting && once) {       window.removeEventListener('scroll', handler);     }   }    window.addEventListener('scroll', handler);     return () => window.removeEventListener('scroll', handler);   }); </script>  <style>   div {     width: 100%;     height: 100%;   } </style>  <div bind:this={container}>   <slot {intersecting}></slot> </div>

Stick this in a file called IntersectionObserver.svelte in a src/components folder. Then, reference it from the main Svelte file: App.svelte.

import IntersectionObserver from "../components/IntersectionObserver.svelte";

Now that we have the Intersection Observer available as a component, we can wrap other elements with it.

<IntersectionObserver let:intersecting top={400}>  {#if intersecting}     <section>       This message will Show if it is intersecting     </section>   {:else}     <section>       This message won't Show if it is intersecting     </section>  {/if} </IntersectionObserver>

That’s really it! You can see how the Intersection Observer component allows us to use <IntersectionObserver>  like a wrapper and define where the intersection should trigger, which is 400 pixels from the top in this example. As a reminder, this is all being exported as vanilla JavaScript! Super performant, no funny business. We’re sandwiching JavaScript and HTML together which is cool because we can see what the Intersection Observer is directly affecting, leaving no ambiguity and without being penalized for performance.

The OnMount function is necessary to tell Svelte that this code needs to run within the browser, as the Intersection Observer can’t be figured out ahead of time.

We’ll need to add some styling so that we can experience the observer in action, and we can do that directly in your App.svelte file. This might look super familiar if you have worked with any of the other front-end frameworks:

<style>   .somesection {     display: flex;     align-items: center;     justify-content: center;     width: 100%;     height: 100vh;   }      .somesection.even{     background: #ccc;   }            .content{     text-align: center;     width: 350px;   } </style>

Finally, we can copy and paste our Intersection Observer element four times to create more intersections. That gives us a mini web app that reactively adds and removes content as it comes into view — perfect to use with media, like lazy-loading. Check out a demo of the final result and be sure to crack open DevTools to see the Intersection Observer

Some final thoughts

My personal recommendation is to give Svelte a try. We’ve only scratched the surface of the framework in this article, but having converted my personal website to Svelte, I can confidently say that it is a pleasure to work with. It is performant, has a brilliant VSCode linter, and best of all, is easy to use. It may be small and new on the block, but I have a keen feeling that it is the relief from bloated “Goliath” frameworks, the “David” that frontend-ers have been looking for.

So should you use Svelte in a real project? Comparing risk and reward definitely comes into play. The community is smaller than other frameworks, meaning you’re likely to find less support and fewer tutorials to guide your along. At the same time, Svelte is in its third generation, meaning most of the gremlins should have been driven away, leaving a lean and reliable framework.

As with anything new, common sense rules, try it out with something non-commercial, take it for a spin, and see how you go.

Is there anything else? Funny you should ask! There are two co-projects that live in the Svelte Ecosystem: Sapper and Native. Sapper is a framework that utilizes Svelte for building full web applications, including routing, service workers, and all the good stuff you need to get started. I have used it to rebuild my personal website, and so far, I am a fan. Svelte Native is the most experimental of the Svelte projects, a NativeScript mobile app builder that utilizes Svelte under the hood. I confess that is where my knowledge on the subject ends. Luckily, it has a website with further information.

What do you think? Have you given Svelte a try? Do you think it stacks up to other frameworks? Let’s discuss it in the comments!

  1. Based on a mix of Github Contributions, NPM Downloads and StackOverflow topics
  2. State of JS review 2019

The post Getting Acquainted With Svelte, the New Framework on the Block appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

What I Like About Writing Styles with Svelte

There’s been a lot of well-deserved hype around Svelte recently, with the project accumulating over 24,000 GitHub stars. Arguably the simplest JavaScript framework out there, Svelte was written by Rich Harris, the developer behind Rollup. There’s a lot to like about Svelte (performance, built-in state management, writing proper markup rather than JSX), but the big draw for me has been its approach to CSS.

Single file components

​​

React does not have an opinion about how styles are defined
—React Documentation

​​​​

A UI framework that doesn’t have a built-in way to add styles to your components is unfinished.
—Rich Harris, creator of Svelte

In Svelte, you can write CSS in a stylesheet like you normally would on a typical project. You can also use CSS-in-JS solutions, like styled-components and Emotion, if you’d like. It’s become increasingly common to divide code into components, rather than by file type. React, for example, allows for the collocation of a components markup and JavaScript. In Svelte, this is taken one logical step further: the Javascript, markup and styling for a component can all exist together in a single `.svelte`​ file. If you’ve ever used single file components in Vue, then Svelte will look familiar.

// button.svelte <style>   button {     border-radius: 0;     background-color: aqua;   } </style>  <button>   <slot/> </button>

Styles are scoped by default

By default, styles defined within a Svelte file are scoped. Like CSS-in-JS libraries or CSS Modules, Svelte generates unique class names when it compiles to make sure the styles for one element never conflict with styles from another.

That means you can use simple element selectors like div and button in a Svelte component file without needing to work with class names. If we go back to the button styles in our earlier example, we know that a ruleset for <button> will only be applied to our <Button> component — not to any other HTML button elements within the page. If you were to have multiple buttons within a component and wanted to style them differently, you’d still need classes. Classes will also be scoped by Svelte.

The classes that Svelte generates look like gibberish because they are based on a hash of the component styles (e.g. svelte-433xyz). This is far easier than a naming convention like BEM. Admittedly though, the experience of looking at styles in DevTools is slightly worse as the class names lack meaning.

The markup of a Svelte component in DevTools.

It’s not an either/or situation. You can use Svelte’s scoped styling along with a regular stylesheet. I personally write component specific styles within .svelte files, but make use of utility classes defined in a stylesheet. For global styles to be available across an entire app — CSS custom properties, reusable CSS animations, utility classes, any ‘reset’ styles, or a CSS framework like Bootstrap — I suggest putting them in a stylesheet linked in the head of your HTML document.

It lets us create global styles

As we’ve just seen, you can use a regular stylesheet to define global styles. Should you need to define any global styles from within a Svelte component, you can do that too by using :global. This is essentially a way to opt out of scoping when and where you need to.

For example, a modal component may want to toggle a class to style the body element:

<style> :global(.noscroll) {   overflow: hidden; } </style>

Unused styles are flagged

Another benefit of Svelte is that it will alert you about any unused styles during compilation. In other words, it searches for places where styles are defined but never used in the markup.

Conditional classes are terse and effortless

If the JavaScript variable name and the class name is the same, the syntax is incredibly terse. In this example, I’m creating modifier props for a full-width button and a ghost button.

<script>   export let big = false;   export let ghost = false; </script>  <style>   .big {     font-size: 20px;     display: block;     width: 100%;   }      .ghost {     background-color: transparent;     border: solid currentColor 2px;   } </style>          <button class:big class:ghost>   <slot/> </button>

A class of ghost will be applied to the element when a ghost prop is used, and a class of big is applied when a big prop is used.

<script>   import Button from './Button.svelte'; </script>  <Button big ghost>Click Me</Button>

Svelte doesn’t require class names and prop names to be identical.

<script>   export let primary = false;   export let secondary = false; </script>  <button   class:c-btn--primary={primary}   class:c-btn--secondary={secondary}   class="c-btn">   <slot></slot> </button>

The above button component will always have a c-btn class but will include modifier classes only when the relevant prop is passed in, like this:

<Button primary>Click Me</Button>

That will generate this markup:

<button class="c-btn c-btn--primary">Click Me</button>

Any number of arbitrary classes can be passed to a component with a single prop:

<script> let class_name = ''; export { class_name as class }; </script>  <button class="c-btn {class_name}">   <slot /> </button>

Then, classes can be used much the same way you would with HTML markup:

<Button class="mt40">Click Me</Button>

From BEM to Svelte

Let’s see how much easier Svelte makes writing styles compared to a standard CSS naming convention. Here’s a simple component coded up using BEM.

.c-card {   border-radius: 3px;   border: solid 2px; }  .c-card__title {   text-transform: uppercase; }  .c-card__text {   color: gray; }  .c-card--featured {   border-color: gold; }

Using BEM, classes get long and ugly. In Svelte, things are a lot simpler.

<style> div {   border-radius: 3px;   border: solid 2px; }  h2 {   text-transform: uppercase; }  p {   color: gray; }  .featured {   border-color: gold; } </style>  <div class:featured>   <h2>What I Like About Writing Styles with Svelte</h2>   <p>     <slot />   </p> </div>

It plays well with preprocessors

CSS preprocessors feels a lot less necessary when working with Svelte, but they can work perfectly alongside one another by making use of a package called Svelte Preprocess. Support is available for Less, Stylus and PostCSS, but here we’ll look at Sass. The first thing we need to do is to install some dependencies:

npm install -D svelte-preprocess node-sass

Then we need to import autoPreprocess in rollup.config.js at the top of the file.

import autoPreprocess from 'svelte-preprocess';

Next, let’s find the plugins array and add preprocess: autoPreprocess() to Svelte:

export default {   plugins: [     svelte({       preprocess: autoPreprocess(),       ...other stuff

Then all we need to do is specify that we’re using Sass when we’re working in a component file, using type="text/scss" or lang="scss" to the style tag.

<style type="text/scss">   $ pink: rgb(200, 0, 220);   p {     color: black;     span {       color: $ pink;     }   } </style>

Dynamic values without a runtime

We’ve seen that Svelte comes with most of the benefits of CSS-in-JS out-of-the-box — but without external dependencies! However, there’s one thing that third-party libraries can do that Svelte simply can’t: use JavaScript variables in CSS.

The following code is not valid and will not work:

<script>   export let cols = 4; </script>  <style>   ul {     display: grid;     width: 100%;     grid-column-gap: 16px;     grid-row-gap: 16px;     grid-template-columns: repeat({cols}, 1fr);   } </style>  <ul>   <slot /> </ul>

We can, however, achieve similar functionality by using CSS variables.

<script>   export let cols = 4; </script>  <style>   ul {     display: grid;     width: 100%;     grid-column-gap: 16px;     grid-row-gap: 16px;     grid-template-columns: repeat(var(--columns), 1fr);   } </style>  <ul style="--columns:{cols}">   <slot /> </ul>

I’ve written CSS in all kinds of different ways over the years: Sass, Shadow DOM, CSS-in-JS, BEM, atomic CSS and PostCSS. Svelte offers the most intuitive, approachable and user-friendly styling API. If you want to read more about this topic then check out the aptly titled The Zen of Just Writing CSS by Rich Harris.

The post What I Like About Writing Styles with Svelte appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]