Upgrade to Pro — share decks privately, control downloads, hide ads and more …

オブジェクト指向CSSが叶えたかったことと、CSSのいま / The aims of Object-oriented CSS and the current state of CSS usage

オブジェクト指向CSSが叶えたかったことと、CSSのいま / The aims of Object-oriented CSS and the current state of CSS usage

Object-Oriented Conference 2024​​ https://ooc.dev/2024/
で喋ったスライドです。

ShinkuFencer

March 24, 2024
Tweet

More Decks by ShinkuFencer

Other Decks in Technology

Transcript

  1. 2009年頃のHTMLとCSS(再現) 6 <html> <head> <meta charset="UTF-8"> <style> /* 中略 */

    #navigation { margin: 0; padding: 10px 50px; border: 1px dotted #ddd; } #navigation ul { padding: 0; } #navigation li { /* 略 */ } #navigation a { /* 略 */ } </style> </head> <body> <section> <div id="navigation"> <ul> <li><a href="">トップページ </a> </li> <li><a href="">おしらせ</a> </li> <li><a href="">更新履歴</a> </li> <li><a href="">問い合わせ </a> </li> </ul> </div> </section> <section> <div id="contents"> ここに本文がはいります </div> </section> </body> </html>
  2. 2009年頃のHTMLとCSS(再現) 7 <html> <head> <meta charset="UTF-8"> <style> /* 中略 */

    #navigation { margin: 0; padding: 10px 50px; border: 1px dotted #ddd; } #navigation ul { padding: 0; } #navigation li { /* 略 */ } #navigation a { /* 略 */ } </style> </head> <body> <section> <div id="navigation"> <ul> <li><a href="">トップページ </a> </li> <li><a href="">おしらせ</a> </li> <li><a href="">更新履歴</a> </li> <li><a href="">問い合わせ </a> </li> </ul> </div> </section> <section> <div id="contents"> ここに本文がはいります </div> </section> </body> </html> IDセレクタを利用して スタイリングの割当を 行っていた
  3. どの詳細度が優先されるかわかりづらい例 12 <html> <header> <style> div p { /* 詳細度は(0,0,2)

    */ color: red; } div p#first { /* 詳細度は(1,0,2) そのため他3つよりもこれが優先 */ color: green; } p#first { /* 詳細度は(1,0,1) */ color: orange; } div p[name="example"] { /* 詳細度は(0,1,2) */ color: yellow; } </style> </header> <body> <div> <p name="example" id="first">sample text</p> </div> </body> </html>
  4. どの詳細度が優先されるかわかりづらい例 13 <html> <header> <style> div p { /* 詳細度は(0,0,2)

    */ color: red; } div p#first { /* 詳細度は(1,0,2) そのため他3つよりもこれが優先 */ color: green; } p#first { /* 詳細度は(1,0,1) */ color: orange; } div p[name="example"] { /* 詳細度は(0,1,2) */ color: yellow; } </style> </header> <body> <div> <p name="example" id="first">sample text</p> </div> </body> </html> 例えばフォントサイズを変更したくても どれに足せばいいのかわからないし 新たに足したら違うものに反映されるかも という怖さがある
  5. OOCSSの考え方 16 • Object Oriented CSS(OOCSS)は2009年にNicole Sullivan 氏によって提唱された • Webページをレゴの集まりのように捉える考え方。

    • そのレゴひとつひとつを他のオブジェクト指向の考え 方になぞらえて”Object”と呼ぶ。
  6. OOCSSにおけるObjectとは? 18 FAQ · stubbornella/oocss Wiki https://github.com/stubbornella/oocss/wiki/FAQ より引用 ①HTML DOMの1つ以上の

    ノード ②CSS宣言 ①に関するStyle ③Objectの表示に 必要な画像など ④Objectに必要な JavaScript OOCSS Object
  7. 命名規則 BEM(Block,Element,Modifier) 37 「Key concepts / Methodology / BEM」より引用 https://en.bem.info/methodology/key-concepts/

    Blockを 構成するパーツを Elementとして捉える パターン違いは Modifierで表現
  8. BEMを利用する場合の例 39 <section class="content"> <h2 class="content__title"> 素敵なタイトル </h2> <div class="content__body">

    素敵な本文素敵な本文 </div> <div class="content__body content__body_alert"> ここは注意を促す文章 </div> </section> .content { max-width: 1000px; padding: 10px 15px; margin-right: auto; margin-left: auto; background-color: #DDC; } .content__title { margin-bottom: 10px; font-size: 1.25rem; font-weight: bold; } .content__body { font-size: 1rem; color: #222; } .content__body_alert { color: #F00; }
  9. 命名規則によって解決されたこと 41 • BEM登場後に「命名規則で行うアプローチ」は多く登 場した ◦ SMACSS ◦ FLOCSS ◦

    SUIT CSS • いずれもBEMとは違う切り口の概念ではあるが、実現 するための手法としてはCSSのclassの名称や組み合わ せで表現している
  10. JavaScript(JS)フレームワークの登場とCSS 45 • 2013年頃からにReactやVue.jsのようなUI Component 指向のフレームワークが登場した • OOCSSで提唱されたObjectの構成要素を考えるとほぼ UI Componentそのもの

    • これらのフレームワークの登場とともに、JSと組み合 わせることでCSSをUI Componentの内部に閉じ込める 仕組みも併せて登場した • 大きくはCSS ModulesとCSS in JSの2種類がある 内部に閉じ込めるという観点ではWeb ComponentsとShadow DOMの仕組みもあるのですが 今回は尺の都合上省略します
  11. CSS Module 46 • ReactなどJSで構成されたUI Component内のみ適用さ れるようにCSSのclass名を自動生成する仕組み • もともとは “css-loader”

    というライブラリの実装だっ たが、CSS Moduleとして仕様化され、他ライブラリの 実装がある
  12. Reactでのcss-loader利用例 47 .error { background-color: red; } Button.module.css import React,

    { Component } from 'react'; import styles from './Button.module.css'; class Button extends Component { render() { // reference as a js object return <button className={styles.error}>Error Button</button>; } } export default Button Button.js
  13. Reactでのcss-loader利用例 48 .error { background-color: red; } Button.module.css import React,

    { Component } from 'react'; import styles from './Button.module.css'; class Button extends Component { render() { // reference as a js object return <button className={styles.error}>Error Button</button>; } } export default Button Button.js JSのコンパイル時にclass名に対して UI Component名やランダムなsuffixをつけ 専用の記述にし衝突回避
  14. Reactでのstyled-components利用例 50 import React from 'react'; import ReactDOM from 'react-dom/client';

    import './index.css'; import styled from "styled-components"; const Button = styled.button<{ daigi?: boolean; }>` background: ${props => props.daigi ? "#BF4F74" : "white"}; color: ${props => props.daigi ? "white" : "#BF4F74"}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid #BF4F74; border-radius: 3px; `; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( <React.StrictMode> <Button>Normal</Button> <Button daigi>Primary</Button> </React.StrictMode> ); index.tsx
  15. Reactでのstyled-components利用例 51 import React from 'react'; import ReactDOM from 'react-dom/client';

    import './index.css'; import styled from "styled-components"; const Button = styled.button<{ daigi?: boolean; }>` background: ${props => props.daigi ? "#BF4F74" : "white"}; color: ${props => props.daigi ? "white" : "#BF4F74"}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid #BF4F74; border-radius: 3px; `; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( <React.StrictMode> <Button>Normal</Button> <Button daigi>Primary</Button> </React.StrictMode> ); index.tsx 表示分岐ロジックを JS(TS)の世界観で記述ができる
  16. CSS ModulesやCSS in JSがもたらしたもの 52 • JavaScriptの管轄する世界でCSSの記述をすると、特定 のパーツの範囲だけ適用されるCSSを記述することがで きる •

    またCSS in JSではTypeScriptも利用可能なため、従来 の型付き言語にあるような恩恵(型安全)なども受け ることができる • JSのUI Componentの構成はOOCSSに近く、CSSの名 付けよりも直感的にObjectを認識できる
  17. 新しいCSS仕様の登場 54 • CSS ModulesもCSS in JSもReactやVue.jsなどのJSの ライブラリを使うことが前提の仕組みなので、それら がないと利用できない •

    2023年ごろ、影響範囲の絞り込みができるCSSの新仕 様が登場した • それらの新仕様を組み合わせることでCSSだけでもJSの UI Component相当の影響範囲の絞り込みをつくること ができるようになってきている
  18. @layerを適用した例 56 <html> <header> <style> /* 一番最後設置された layerから優先して反映される ,そのため赤文字になる */

    @layer default_layer, power_orange, super_red; @layer default_layer { /* 詳細度は(1,0,2) */ div p#first { color: green; } /* 詳細度は(0,1,2) */ div p[name="example"] { color: yellow;} } @layer super_red { /* 詳細度は(0,0,2) */ div p { color: red;} } @layer power_orange { /* 詳細度は(1,0,1) */ p#first {color: orange;} } </style> </header> <body> <div> <p name="example" id="first">sample text</p> </div> </body> </html>
  19. @scopeの使用例 58 <style> @scope( [data-component='normal-card'] ) { .card { width:

    288px; height: auto; box-shadow: 2px 2px 6px rgba(0, 0, 0, .4); } .text_box { width: 100%; height: auto; padding: 20px 18px; background: #ffffff; box-sizing: border-box; } .title_text { font-size: 24px; font-weight: bold; line-height: 125%; } .overview_text { font-size: 18px; line-height: 150%; } } @scope( [data-component='mini-card'] ) { .card { width: 144px; height: auto; box-shadow: 2px 2px 6px rgba(0, 0, 0, .4); } .text_box { width: 100%; height: auto; padding: 20px 18px; background: #ffffff; box-sizing: border-box; } .title_text { font-size: 20px; font-weight: bold;line-height: 125%; } .overview_text { font-size: 12px; line-height: 150%; } } </style> <body> <div data-component='normal-card'> <div class="card"> <div class="text_box"> <div class="title_text">タイトル</div> <div class="overview_text"> ここには文章がはいります文章が入ります </div> </div> </div> </div> <br> <div data-component='mini-card'> <div class="card"> <div class="text_box"> <div class="title_text">タイトル</div> <div class="overview_text"> ここには文章がはいります文章が入ります </div> </div> </div> </div> </body>
  20. @scopeの使用例 59 <style> @scope( [data-component='normal-card'] ) { .card { width:

    288px; height: auto; box-shadow: 2px 2px 6px rgba(0, 0, 0, .4); } .text_box { width: 100%; height: auto; padding: 20px 18px; background: #ffffff; box-sizing: border-box; } .title_text { font-size: 24px; font-weight: bold; line-height: 125%; } .overview_text { font-size: 18px; line-height: 150%; } } @scope( [data-component='mini-card'] ) { .card { width: 144px; height: auto; box-shadow: 2px 2px 6px rgba(0, 0, 0, .4); } .text_box { width: 100%; height: auto; padding: 20px 18px; background: #ffffff; box-sizing: border-box; } .title_text { font-size: 20px; font-weight: bold;line-height: 125%; } .overview_text { font-size: 12px; line-height: 150%; } } </style> <body> <div data-component='normal-card'> <div class="card"> <div class="text_box"> <div class="title_text">タイトル</div> <div class="overview_text"> ここには文章がはいります文章が入ります </div> </div> </div> </div> <br> <div data-component='mini-card'> <div class="card"> <div class="text_box"> <div class="title_text">タイトル</div> <div class="overview_text"> ここには文章がはいります文章が入ります </div> </div> </div> </div> </body> 特定の条件に該当するときだけ 適用されるCSSを指定することが できる
  21. UI ComponentとCSSの立ち位置の変化 67 • OOCSS登場当時はCSSのclass名がObject名を表現する のが最適解だったため、Objectの意味のある名付けは CSSが担っていた • 近年Webページを構成する主体がJSフレームワークに 移り変わってきた

    • 結果としてセマンティックな名付けをされる対象もCSS からJSのUI ComponentなどCSSではないところが主体 になることが増えた このスライドではJSのUI Componentの話を中心にしてきたが パーツをWebアプリケーションフレームワークの部分テンプレート(Railsのpartialなど)が 担うことも可能なので、JSを利用しない場合でも名付けをCSS外に移譲できる
  22. 従来のセマンティックなCSSで作る例 72 <div class="chat-notification"> <div class="chat-notification-logo-wrapper"> <img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat

    Logo"> </div> <div class="chat-notification-content"> <h4 class="chat-notification-title">ChitChat</h4> <p class="chat-notification-message">You have a new message!</p> </div> </div> Utility-First Fundamentals - Tailwind CSS https://tailwindcss.com/docs/utility-first よりサンプルコードを引用 <style> .chat-notification { display: flex; max-width: 24rem; margin: 0 auto; padding: 1.5rem; border-radius: 0.5rem; background-color: #fff; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); } .chat-notification-logo-wrapper { flex-shrink: 0; } .chat-notification-logo { height: 3rem; width: 3rem; } .chat-notification-content { margin-left: 1.5rem; padding-top: 0.25rem; } .chat-notification-title { color: #1a202c; font-size: 1.25rem; line-height: 1.25; } .chat-notification-message { color: #718096; font-size: 1rem; line-height: 1.5; } </style> 順当にObjectの”意味”に 基づいた名前を設定している
  23. Tailwind CSSでの記述例 73 <div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg

    flex items-center space-x-4"> <div class="shrink-0"> <img class="h-12 w-12" src="/img/logo.svg" alt="ChitChat Logo"> </div> <div> <div class="text-xl font-medium text-black">ChitChat</div> <p class="text-slate-500">You have a new message!</p> </div> </div> Utility-First Fundamentals - Tailwind CSS https://tailwindcss.com/docs/utility-first よりサンプルコードを引用
  24. Tailwind CSSでの記述例 74 <div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg

    flex items-center space-x-4"> <div class="shrink-0"> <img class="h-12 w-12" src="/img/logo.svg" alt="ChitChat Logo"> </div> <div> <div class="text-xl font-medium text-black">ChitChat</div> <p class="text-slate-500">You have a new message!</p> </div> </div> Utility-First Fundamentals - Tailwind CSS https://tailwindcss.com/docs/utility-first よりサンプルコードを引用 CSSのclassが “機能”単位で名付けされ それらを組み合わせて スタイリングを行う
  25. 81 【書籍】 • CSS設計完全ガイド ~詳細解説+実践的モジュール集 - 技術評論社 https://gihyo.jp/book/2020/978-4-297-11173-1 • Web制作者のためのCSS設計の教科書

    モダンWeb開発に欠かせない「修正しやすいCSS」の設計手法 - インプ レスブックス https://book.impress.co.jp/books/1113101128 • Tailwind CSS実践入門 - 技術評論社 ★オススメ https://gihyo.jp/book/2024/978-4-297-13943-8 【WEBサイト】 • 恐竜に教える現代のCSS – Part 1 | POSTD https://postd.cc/actualize-networkmodern-css-explained-for-dinosaurs/ • 知っておきたいCSS設計法 | 第1回 OOCSSの基本 https://www.codegrid.net/articles/2014-css-template-1/ • stubbornella/oocss: Object Oriented CSS Framework https://github.com/stubbornella/oocss • BEM https://en.bem.info/ • Utility-first CSS(Tailwind CSS)が合理的であることの説明と、CSSによるUI開発小史 | blog.tai2.net https://blog.tai2.net/utility-first-css.html • CSS設計って最近こういう感じだと思うんですけどどうですか - Speaker Deck https://speakerdeck.com/takazudo/cssshe-ji-tutezui-jin-kouiugan-zidatosi-undesukedodoudesuka • Now and Next Generation of CSS Cascading Model | ドクセル https://www.docswell.com/s/araya/51JEY8-fec-okinawa-2023
  26. 82 【WEBサイト】 • CSS Modulesの歴史、現在、これから - Hatena Developer Blog https://developer.hatenastaff.com/entry/2022/09/01/093000

    • ZOZOTOWN Webフロントエンドリプレイスにおける CSS in JS の技術選定で Emotion を選定した話 - ZOZO TECH BLOG https://techblog.zozo.com/entry/zozotown-css-in-js • うひょさん、よしこさんと改めて考えるReactコンポーネント設計 | Offers Magazine https://offers.jp/media/event-report/a_3060 • 次世代 CSS 仕様が与えるコンポーネント時代の Web への影響 | blog.jxck.io https://blog.jxck.io/entries/2023-01-07/new-css-capabilities-for-component.html • Cascade Layerは汚れ切ったCSSの救世主になれるのか? https://zenn.dev/kyoheyee/articles/6bbc6f1dc55d0b • CSSにそのうち導入されそうな@scopeとその関連概念 https://zenn.dev/uhyo/articles/css-cascading-6-scope