Styles
Global styles
Inside lib/styles, there are a number of stylesheets. These are:
global.css: contains overall styling for the app and imports the stylesheets below._fonts.css: contains imports for Google fonts that are used by the app._colors.css: contains colors for the app with variations for light and dark mode._reset.css: contains styles that sand down some of the rough edges in the CSS language (based on Josh Comeau's CSS reset)._animations.css: contains animations for the app.
Partial CSS files (prefixed with underscore) are imported as opposed to lumping everything into one massive global.css file. This separates respsonsibilites and makes global styling easier to maintain.
Keep in mind that all the CSS stylesheets are loaded once and persist as long as the app is running. Navigating to another page (via a typical client-side route change in SvelteKit) does not 'unload' the stylesheet. This means that you cannot import a stylesheet like app.css and expect it to only apply to certain components/pages because when the user navigates away, the styles will persist, potentially affecting other pages.
Scoped styles
In general, the recommended approach to styling is using scoped styles within each Svelte component (inside the style tag). This ensures that styles do not leak between components and can allow CSS class names to stay simple like 'container'.
If you want the same styles to be shared my multiple components/pages in the app, you can create a CSS class in theglobal.css file as mentioned in the previous section..
Components
Most web apps typically rely on a set of common primitive UI components like modals, dropdown menus, popovers, tooltips etc. SvelteStart comes with many such primitives (found in lib/components/primitives).
Melt UI is a headless UI component builder library that offers low-level building blocks that handle the logic and accessibility, while leaving the stlying up to the developer. Most of SvelteStart's primitive UI components utilise these builders. You can also implement your components with the builders from Melt UI.
Note that Melt UI was chosen over Bits UI, which is a more traditional headless component library because that does not support scoped styles. Melt UI is a lower-level and is actually used under the hood by Bits UI.
Responsive design
SvelteStart is built with responsiveness in mind, ensuring full usability in tablet, mobile and laptop devices. However, it focuses on a desktop-first design (rather than mobile-first), meaning layouts are primarily designed for larger screens and then adapted downwards. To achieve this, media queries with max-width conditions are used to progressively adjust for smaller devices.
This can be done with traditional CSS by using the following:
@media (max-width: 600px): for mobile devices@media (max-width: 1200px): for tablet devices@media (max-width: 1800px): for laptop devices
You also don't need to rely on these typical device breakpoints. Instead, you can use content-driven breakpoints. In other words, the max-width value can be flexibly set based on your specific needs i.e. when the layout actually fails, rather than trying to adjust to tablet/mobile/laptop.
Breakpoints are also available programatically in JavaScript via lib/utilities/Breakpoint.svelte.ts. This allows components to react to viewport changes at runtime e.g. conditionally rendering different layouts or toggling navigation styles.
Animations
Custom keyframe animations such as fading in, scaling etc. are defined in _animations.css. These can then be used throughout the app via the CSS animation property e.g. animation: fade-in 0.3s ease;.
Transiton and Animate directives are imported from the Svelte library to be used in Svelte files.
Transitions control how an element enters and leaves the DOM. This typically happens when an element is first mounted or when it is conditionally added or removed with an if or each block.
The transition directive is more powerful than a traditional CSS keyframe animation as it allows you to do an exit transition which is not possible with plain CSS. It is also composable, meaning that you can define an entrance or an exit transition separately via in: and out: or both with transition:.
Additionally, slide transitions are especially powerful because when the sliding element enters or exits, anything beneath it will also slide accordingly (to make room or fill up room).
Note that motion-heavy transitions like slide, fly etc. should be imported from the custom lib/utilities/motionTransition.js file as these will respect the user's "reduce motion" OS setting for better accessibility. Some users experience motion sickness or dizziness from heavy animations so it is important to respect this.
Finally, the animate directive is used to create smooth animations when the contents of a keyed each block are reordered. This can add polish to dynamic lists where you are doing sorting or filtering. However, since such scenarios are less common, you'll likely use this directive less often than the transition directive in your app.
Last updated