LP作って〜って言われたので、ほな Svelte でやってみよっかな〜と思い Svelte に入門しました。
Svelte はデフォルトでは CSS in JS でスコープのあるスタイルが書けるのですが、共通して使いまわしているコンポーネントのスタイルを親コンポーネントで指定するのにちょいハマったのでメモ。
Svelte プロジェクトの作成
$ npx degit sveltejs/template my-project $ cd my-project $ npm install # TypeScript 化 (設定勝手にやってくれる) $ node scripts/setupTypeScript.js # Sass 使えるようにする $ npm i -D sass
Sass の利用は TypeScript 化をしていたからなのかは不明ですが sass
をインストールするだけで特に設定をしなくても .svelte
ファイル内で <style lang="scss">
とすれば使えるようになりました。
- svelte: ^3.0.0
- rollup: ^2.3.4
- typescript: ^4.0.0
- sass: 1.37.5
小コンポーネントのスタイルを親コンポーネントで指定する
Logo コンポーネント
// src/Logo.svelte <img class="logo" src="/images/logo.svg" alt="ロゴ" />
App コンポーネント
// src/App.svelte <script lang="ts"> import Logo from './Logo.svelte'; </script> <main role="main"> <Logo /> </main> <style lang="scss"> .logo { widh: 100px; } </style>
App コンポーネントから Logo の width
を指定したいけど、Svelte の <style>
は書かれている DOM だけをスコープにするようで、上記では上手く動作しません
:global
を使う方法
:global(selector)
でスコープのないグローバルなクラスが作成できることを利用して、このコンポーネントのクラス :global(子コンポーネントのクラス)
で該当コンポーネントの時だけ該当するスタイルになる
// src/App.svelte // Logo => <img class="logo" src="/images/logo.svg" alt="ロゴ" /> <main class="main" role="main"> <Logo /> </main> <style lang="scss"> .main :global(.logo) { widh: 100px; } </style>
この方法は global な CSS としてスタイルが作成されるので、親コンポーネントから子コンポーネントのスタイルを作成することができます。
ただ、親コンポーネントが子コンポーネントのクラス名やタグ名などの内部実装を知っていなければならないのでチョット微妙です。
cf. CSS Modules やっていき - かもメモ :global
とか :local
についてのメモ
親コンポーネントからスコープ付きのクラス名を渡す方法
必要なパッケージのインストール
$ npm i -D svelte-preprocess-cssmodules svelte-as-markup-preprocessor
ビルドの設定の変更
rollup.config.js
+ const cssModules = require('svelte-preprocess-cssmodules'); + const { asMarkupPreprocessor } = require('svelte-as-markup-preprocessor'); // … export default { // … plugins: [ svelte({ - preprocess: sveltePreprocess({ sourceMap: !production }), + preprocess: [ + asMarkupPreprocessor([ + sveltePreprocess({ sourceMap: !production }), + ]), + cssModules(), + ], compilerOptions: { // enable run-time checks when not in production dev: !production }, }), ],
親コンポーネントからクラス名を指定できるようにする
/src/Logo.svelte
<script lang="ts"> const addClass = $$restProps.class || ''; const className = [...new Set(['logo', addClass])].join(' '); </script> <img class={className} src="/images/logo.svg" alt="ロゴ" />
親コンポーネントで子コンポーネントのスタイルを指定する
src/App.svelte
<script lang="ts"> import Logo from './Logo.svelte'; </script> <main role="main"> <Logo class="main-logo" /> </main> // module 属性を付ける <style lang="scss" module> .main-logo { widh: 100px; } </style>
ポイントは親コンポーネントの <style>
に module
属性を付けることです! module
属性が無いと子コンポーネントに上手くスタイルが設定できませんでした。
cf. Support classes on nested components by nikku · Pull Request #2888 · sveltejs/svelte · GitHub
⚠ <style module>
の時に気をつけること
<style module>
の時 p {}
のようなタグでスタイルを指定していると意図せず global なスタイルを作成してしまう事になるので注意が必要です
module
でない時
<section> My Content </section> <style lang="scss"> section { width: 100%; } </style>
👇 コンパイルするとタグ指定のものは自動でクラス名が付けられる
<section class="svelte-1dsdi5i"> My Content </section> <style> section.svelte-1dsdi5i { width: 100%; } </style>
module
の時
<section> My Content </section> <style lang="scss" module> section { width: 100%; } </style>
👇 コンパイルしてもタグ指定のままになる
<section> My Content </section> <style> section { width: 100%; } </style>
全ての <section>
に適応されるクラスになってしまう!!!
Svelte でスタイルを <style module>
にする時は必ずクラスを付けてスタイルを適応したほうが安全!
これで npm run dev
又は npm run build
で確認すると .main-logo
のクラス名がハッシュ化され Logo コンポーネントに渡され App コンポーネントで指定したスタイルが適応されるようになりました!
₍ ᐢ. ̫ .ᐢ ₎ A W E S O M E !
おわり
新しい事を学ぶのは楽しい!
納期が無ければもっと楽しい…!!
だが、納期がないと手を付けない…!!!!
[参考]
- Svelte • Cybernetically enhanced web apps
- API Docs • Svelte
- javascript - Style children from parent using a class - Stack Overflow
- How to apply styles to slot element in Svelte? - Stack Overflow
- Support classes on nested components by nikku · Pull Request #2888 · sveltejs/svelte · GitHub
- Svelteとは
- Svelteで始める頑張らないフロントエンド生活 前編
- Svelte + TypeScript + SCSS やってみる - Neo's World
- Svelte に TypeScript と Sass を導入する - Qiita