1
votes

Component B is included as a part of the slot html for the Component A. The code below doesn't work as it may be expected, because components don't share styles by default (svelte-${hash(css)} is used to make a set of different "virtual" namespaces during the compilation):

// Component A - ./Menu.svelte

<Router>
    <ul class="menu">
        <Delimiter label={$format('Menu label')}></Delimiter>

        {#each routes as route}
            {#if route.url?.length > 0}
            <li class="menu-item">
                <Link to={route.url} getProps={onLinkUpdate}>
                    {route.title}
                </Link>
            </li>
            {/if}
        {/each}
    </ul>
</Router>
// Component B - ./Menu/Delimiter.svelte

<li class="divider" data-content={label} {...$$restProps} />

Router and Link here are parts of the separate package (so, considering as a Namespace A). Delimiter is a project-level component (Namespace B). They all use the same style sheets, i.e. the same CSS framework environment.

An example above has been compiled into something like this:

<ul class="menu">
    <li class="divider" data-content="..."></li>
    <li class="menu-item">...</li>
</ul>

And li with divider class didn't receive its styles. But if the Delimiter component (this line):

<Delimiter label={$format('Menu label')}></Delimiter>

will be replaced with its direct contents:

<li class="divider" data-content="..."></li>

The compiled source will be like:

<li class="divider svelte-sipu9k" data-content="..."></li>

So, the question is - how to properly "share" a style base with the external components, which are included (nested) to the original namespace? (or is it an architecture problem and I should try a different approach?)

1
Where is your CSS coming from? If it's coming from an external stylesheet and your components are not getting styled then something is wrong. But the scenario you're describing is one where a parent component has some styles defined inside it and you want them to cascade down to nested components.JHeth
Parent component have a .scss file included: <style src="./Menu.scss"></style>, this file describes styling for the .divider class, without any :global (or similar) directives. Just an @import from the framework's code base.itnelo

1 Answers

0
votes

I will post an answer to my own question, because, if I understood the framework correctly, there should not be any "cascading" at all. It seems that the original problem was not with the styles sharing. It was a result of an implicit "tree-shaking" analogue for the CSS code base. Svelte didn't detect CSS usage for the Child components (those styles are described in the Parent component, but were not used directly in the same template, so they are removed from the .css output completely). I found some workarounds, how to "cascade" styles down to the child components properly. Solutions, which are worked for me (tested with Svelte 3.*):

Way 1 (preferable)

Actually, write component-based styles, without any cascading (as it's recommended by default).

./Delimiter.svelte

<script type="text/javascript">
    export let label = '';
</script>

<template src="./Delimiter.html"></template>

<style src="./Delimiter.scss"></style>

./Delimiter.html

<li class="divider" data-content={label} {...$$restProps} />

./Delimiter.scss

@import 'spectre.css/src/utilities/divider';

Now, if you include this component as a "nested" one, it will add an additional svelte-hash class to your node and the output .css will contain a set of namespace-based styles (e.g. .divider.svelte-n3dv4p).

Example:

<li class="divider svelte-n3dv4p" data-content="..."></li>

Way 2

This is exactly what I wanted to avoid using a component-based framework - global styles. It seems there are no (documented?) way to make a "group" of nested components, to make them share a couple of styles (e.g. a group, containing a set of components from the third-party packages and a project-level component). It is a strict component-based or "all global" approach (am I wrong here?).

So, if you have a convenient, some kind of root-level component with "global" styles block, it is possible to add styles here and there will be no svelte-hash classes and namespace suffixes in your .css output. I don't like this way too much, because it breaks an original idea about component namespaces and encapsulation, but I have to do it in some cases (when the styles are "dynamic", i.e. compiler is unable to parse them from the template files directly). An example from one of my projects:

/**
 * This file represents a set of styles for the application component.
 * It also includes global styles (e.g. html, body overrides) and normalization for different browsers.
 * Core blocks, elements and modifiers are provided by the Spectre.css framework (https://github.com/picturepan2/spectre).
 */

// managed by Svelte Preprocess using PostCSS (https://github.com/postcss/postcss)
:global {
    @import 'spectre.css/src/normalize';
    @import 'spectre.css/src/base';

    @import 'spectre.css/src/utilities/cursors';
    @import '_styles/typography';

    // for pages
    @import 'spectre.css/src/utilities/position';
    @import 'spectre.css/src/icons/icons-core';
    @import 'spectre.css/src/icons/icons-navigation';
    @import 'spectre.css/src/accordions';
    @import 'spectre.css/src/codes';

    @import '_styles/layout';
    @import '_styles/page';
    @import '_styles/github';
}