すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

クリーンなデザインコード:BEMとSassの実践

この記事で出来るようになること

はじめに

概要

この記事では、「クリーンなデザインコード:BEMとSassの実践」をテーマに、Webデザインの効率化とメンテナンス性の向上を目指します。具体的には、BEM(Block, Element, Modifier)命名規則の適用とSCSSの利用方法に焦点を当てます。これらの技術を活用することで、CSSの構造をより明確にし、スタイルシートの再利用性と保守性を高めることを目的としています。

目標

この章の目標
  • BEM命名規則を理解し、クラス名の付け方でコードの可読性を高める方法を学ぶ。
  • SCSSを使って、CSSの構造をより効率的に管理し、スタイルの再利用性を向上させる技術を習得する。
  • 効率的なWebデザインのためのBEMとSCSSの組み合わせ方を理解する。

BEM

BEMとは、Block(ブロック)・Element(要素)・Modifier(修飾)の頭文字を取ったものです。これはCSSの設計方法の一つで、厳格なクラス名の命名規則が特徴です。

命名規則
1
block__element--modifier

BEMを使用することで、HTMLだけを見てもスタイルを予測しやすくなり、長期的なメンテナンス性の向上や開発スピードを上げることができます。

Block(ブロック)は、Element(要素)で構成されます。

HTML | BlockとElementの関係
1
2
3
4
<div class="search"> <!-- Block -->
  <input class="search__input"> <!-- Element -->
  <input class="search__btn"> <!-- Element -->
</div>

Modifier(修飾)は、BlockやElementの「スタイル」や「状態」を修飾します。
以下の例で、content--yellowはModifierに該当します。

HTML | Modifierの使い方
1
2
3
4
<div class="content content--yellow">  <!-- Modifier -->
  <img class="content__img" src="">
  <div class="content__txt">テキスト</div>
</div>

BEMは、クラス名が長くなることでCSSの記述が複雑になる可能性がありますが、あとで学習するSassなどのCSSプリプロセッサを利用することで、この問題は解決可能です。

それでは1つ1つの要素を見ていきましょう!

ぴかわかさん
ポイント
  1. BEMは厳格なクラス名の命名ルールを持つCSS設計方法の一つ
  2. BEMはBlock(ブロック)、Element(要素)、Modifier(修飾子)の略
  3. 長期的なメンテナンス性が向上し、開発スピードを加速できる

Block(ブロック)

Webページは、ヘッダー、フッター、ナビゲーション、サイドバー、メインコンテンツなどのパーツで構成されています。これらの独立したパーツはそれぞれ、Block(ブロック)に該当します。

Block(ブロック)には、以下の特徴があります。

  • Blockは独立して機能する。
  • BlockはWebページの一部分で、他の場所でも再利用可能。
  • Blockは他のBlockを含めることが可能。

例えば、ヘッダー、フッター、検索フォームといった要素は、他のページで再利用可能なパーツです。これらはそれぞれ「Header block」「Footer block」「Search block」として定義されます。

また、「Header block」内に「Nav block」を配置することが可能です。このように、Blockは他のBlockを含むことができます。

次に検索フォームを例にしてみましょう。検索フォームは、Webページを構成するパーツの一つです。このパーツはBlockとして扱うことができます。

上記の検索フォームには、「入力欄」や「送信ボタン」といった要素が含まれており、Blockとして定義するには外側のdiv要素にsearchというクラスを付与します。

HTML
1
2
3
4
<div class="search"> <!-- Block -->
<input type="search"> <input type="submit">
</div>

BEMの命名規則によると、block__element--modifierの形式のうち、一番左側がblockに相当します。このため、二重アンダースコア(__)や二重ハイフン(--)を使わずにsearchというクラス名を使用します。

このようにBlock単体のクラス名には、二重アンダースコア(__)や二重ハイフン(--)を使用しません。

ぴかわかさん
ポイント
  1. Blockは独立して機能し、Webページの再利用可能なセクションを形成する
  2. Blockは他のBlockを内包することができる
  3. Blockのみのクラス名は、二重アンダースコアや二重ハイフンを使用しない

Element(要素)

Element(要素)はBlockを構成する部分です。ElementはBlockに属すため、Elementのクラス名には必ずBlockのクラス名が含まれることになります。

Elementのクラス名でBlock名を含める際には、二重アンダースコア(__)を使用してBlock名とElement名を区切ります。

検索フォームを例に見てみましょう。
検索フォームの入力欄と送信ボタンは、「Search block」を構成する要素(Element)です。

検索フォームをBlockとElementで表現する場合、以下のように記述します。

HTML | BlockとElementで表現する場合
1
2
3
4
<div class="search"> <!-- Block -->
<input type="search" class="search__input"><!-- Element -->
<input type="submit" class="search__btn"><!-- Element -->
</div>

BEMの命名規則に従い、Elementのクラス名はblock__elementの形式である必要があります。この形式では、Block名に続けてElement名を指定します。このルールにより、ElementがどのBlockに属しているかが明確になります。

上記の例では、「search」というBlockに属する入力欄と送信ボタンのElementは、それぞれsearch__inputsearch__btnというクラス名で表されます。

さらに、「Nav block」のElementの例のように、ElementはBlock内で繰り返し使用することができます。ナビゲーションの「Home」、「About」、「Contact」ボタンなど、表示する文言は異なりますが、これらはスタイルが同じElementとして扱われます。

例えば、以下のように表現できます。

HTML
1
2
3
4
5
6
<!-- Nav block -->
<nav class="nav"> <!-- Block -->
  <a href="/home" class="nav__link">Home</a> <!-- Element -->
  <a href="/about" class="nav__link">About</a> <!-- Element -->
  <a href="/contact" class="nav__link">Contact</a> <!-- Element -->
</nav>

上記では、「nav」というBlock内に複数の「nav__link」というElementが配置されています。これらのElementは、異なるリンク先を指すものの、スタイルは共通しています。

ポイント
  1. Elementは、Blockを構成する要素のこと
  2. ElementはBlockに属しているため、Blockのクラス名を必ず含める
  3. BlockとElementの関係は、二重アンダースコア(__)で表現される

BEMのBlockとElementを使ってスタイリングしよう

これまでの学習でBEMのBlockとElementの基本について理解を深めました。それでは、具体的にアプリケーションにBEMのBlockとElementを使用してスタイルを適用してみましょう。

ヘッダー部分にBEMを適用してみましょう

まず、ヘッダー部分のスタイリングを変更してみましょう。ここで、headerはBlockを表し、header__titleはそのBlock内のElementを表します。

app/views/shared/_header.html.erb | 変更前
1
2
3
<header class="header">
  <h1 class="header-title">社員管理アプリケーション</h1>
</header>
app/views/shared/_header.html.erb | 変更後
1
2
3
<header class="header">
<h1 class="header__title">社員管理アプリケーション</h1>
</header>
フッター部分にBEMを適用してみましょう

次に、フッター部分のスタイリングもBEMに沿って変更してみましょう。footerはBlockを、footer__textはElementを表します。

app/views/shared/_footer.html.erb | 変更前
1
2
3
<footer class="footer">
  <p class="footer-text">&copy; <%= Time.now.year %> Made by Pikawaka Challenge Lesson</p>
</footer>
app/views/shared/_footer.html.erb | 変更後
1
2
3
<footer class="footer">
<p class="footer__text">&copy; <%= Time.now.year %> Made by Pikawaka Challenge Lesson</p>
</footer>
メインコンテンツ部分にもBEMを適用しましょう

さらに、アプリケーションのメインコンテンツ部分にもBEMを適用してみましょう。mainがBlockを、main__contentがElementを表します。

app/views/layouts/application.html.erb | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
  <head>
    <!-- ...省略...-->
  </head>

  <body>
    <%= render 'shared/header' %>
    <%= render 'shared/flash-message' %>

<main class="main">
<div class="main__content">
<%= yield %> </div> </main> <%= render 'shared/footer' %> </body> </html>
社員情報のフォーム部分にBEMを適用しましょう

社員情報のフォーム部分にBEMを適用し、スタイリングを整えてみましょう。

ここではemployee-formではなくformをBlockとします。その内部のform__errorsform__groupform__submitがElementを表します。

app/views/employees/_form.html.erb | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%= form_with model: employee, local: true, class: 'form' do |f| %>
<% if employee.errors.any? %>
<div class="form__errors">
<h3><%= employee.errors.count %>件のエラーが発生しました</h3> <ul> <% employee.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %>
<div class="form__group">
<%= f.label :name, '名前(必須):' %> <%= f.text_field :name %> </div>
<div class="form__group">
<%= f.label :birthday, '生年月日:' %> <%= f.date_field :birthday %> </div>
<div class="form__group">
<%= f.label :department_id, '部署:' %> <%= f.collection_select :department_id, departments, :id, :name %> </div>
<div class="form__submit">
<%= f.submit button_text, class: 'form__button' %>
</div> <% end %> <%= link_to '社員情報一覧に戻る', employees_path %>
詳細画面の削除ボタンにBEMを適用しましょう

詳細画面にある削除ボタンにBEMの命名規則を適用します。ここでは、employee-buttonをBlockとして扱い、link_toのクラス名をdelete-buttonからemployee-button__deleteに変更して、Elementとして定義しましょう。

app/views/employees/show.html.erb | 変更後
1
2
3
4
5
6
7
<%# ...[中略]... %>

<%= link_to '社員情報一覧に戻る', employees_path %>

<div class='employee-button'>
<%= link_to '削除', employee_path(@employee), method: :delete, data: { confirm: '本当に削除してよろしいですか?' }, class: 'employee-button__delete' %>
</div>
layout.scssのクラス名も変更しましょう

最後に、BEMに変更したクラス名をlayout.scssにも適用し、スタイル定義を更新しましょう。変更箇所が複数あるため、コピー&ペーストでの更新作業でも問題ありません。

app/assets/stylesheets/layout.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
body {
  display: flex;
  flex-direction: column;
}

.header {
  padding: 16px;
  box-shadow: 0 0 15px #e2e6ef;
  background-color: #fff;
}

.header__title {
color: #525fe1; font-size: 28px; } .notice { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; color: #3c763d; background-color: #dff0d8; border-color: #d6e9c6; }
.form__errors {
padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; color: #a94442; background-color: #f2dede; border-color: #ebccd1; }
.form__errors h3 {
margin-top: 0; color: inherit; }
.form__errors ul {
margin: 0; padding: 0; list-style-type: none; }
.form__errors li {
margin-bottom: 10px; }
.main {
flex: 1; margin-top: 30px; padding: 0 20px; }
.main__content {
margin: 0 auto; width: 66%; }
.main__content h2 {
font-size: 26px; } .employee-navigation { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } table { margin: 25px 0; } table th { background-color: #ffd099; padding: 10px 20px; } table td { background-color: #fff2e2; padding: 10px 20px; } .employee-button { padding-top: 20px; margin-bottom: 60px; }
.employee-button__delete {
display: inline-block; border-radius: 4px; padding: 10px 30px; background-color: #efefef; text-decoration: none; color: #333; }
.form {
margin: 25px 0; }
.form__group {
margin-bottom: 30px; } select, input[type="text"], input[type="date"] { width: 100%; height: 42px; border: 1px solid #c0c6d6; border-radius: 2px; padding: 10px 16px; margin: 8px 0; }
.form__submit {
text-align: center; padding-top: 20px; font-weight: 700; margin-bottom: 60px; }
.form__button {
border-radius: 4px; padding: 10px 30px; text-align: center; } .footer { margin-top: 70px; padding: 6px; background: #525fe1; }
.footer__text {
color: #fff; text-align: center; font-size: 12px; margin: 0; }
ぴっかちゃん

BEMを使うと、クラス名が長くなってちょっと見づらいかも。

たしかにBEMはクラス名が長くなるけど、これからSCSSの学習で、その点はクリアにできるから安心してね。

ぴかわかさん
layout.scssを変更した後は、スタイルが崩れていないかWebブラウザで確認し、問題がなければ次へ進みましょう!

Modifier(修飾子)

Modifier(修飾子)は、既存のBlockやElementの見た目や状態を「部分的」に変更するために使用します。同じBlockやElementであっても、部分的に異なるスタイルや振る舞いを持たせることができます。

ModifierはBlockまたはElementに適用されるため、Modifierのクラス名には必ずBlockまたはElementのクラス名が含まれることになります。

BlockにModifierを適用する際には、ハイフン2つ(--)を使用してBlock名とModifierを区切ります。Elementに対しても同様です。

Modifierの定義
1
2
3
4
5
<!-- Blockに対する修飾 -->
block--modifier

<!-- Elementに対する修飾 -->
block__element--modifier

ナビゲーションの「Home」、「About」、「Contact」リンクで、「Home」が選択された状態で背景色を変更し、異なるスタイルを適用する例で見てみましょう。

ナビゲーションの各リンクは、Elementです。BEMの命名規則に従い、Elementのクラス名はblock__elementの形式である必要があります。そのため、ElementにModifierを適用する場合はblock__element--modifierの形式にします。

ナビゲーションの「Home」リンクにのみnav__link--activeクラスを付与し、背景色を変更するスタイルを追加します。

HTML
1
2
3
4
5
6
<!-- Nav block -->
<nav class="nav"> <!-- Block -->
  <a href="/home" class="nav__link nav__link--active">Home</a> <!-- Element with Modifier -->
  <a href="/about" class="nav__link">About</a> <!-- Element -->
  <a href="/contact" class="nav__link">Contact</a> <!-- Element -->
</nav>

このようにModifierを活用することで、より細かいデザインの調整や状態の管理が行えるようになります。

ポイント
  1. Modifier(修飾子)は、既存のBlockやElementの見た目や状態を部分的に変更する場合に使う
  2. Modifierのクラス名には、適用されるBlockまたはElementのクラス名が必ず含まれ、ハイフン2つ(--)で区切られる

次はSCSSについて学習します。CSSよりも、コードの記述量が減って保守性が高まるので、人為的なミスを減らすことができます。

ぴかわかさん

SCSS

SCSSはSassの記法の一つです。SassはCSSを拡張したメタ言語(言語を定義する為の言語)です。CSSに似た構文を持ちながら、変数、ネスト、ミックスインなどの機能を提供し、CSSの記述をより効率的かつ柔軟にします。

BEMのデメリットは、クラス名が長くなりがちでCSSの記述が冗長になる点ですが、BEMと親和性の高いSCSSを使用することで、効率的にコーディングを行うことが可能です。

以下のHTML例では、BEMを使用してクラス命名されています。この場合、CSSではクラス名が長くなる傾向があります。

HTML | BEMを使用してクラス名が命名されている場合
1
2
3
4
<div class="search"> <!-- Block -->
  <input class="search__input"> <!-- Element -->
  <input class="search__btn"> <!-- Element -->
</div>

通常のCSSでは以下のように記述します。

例 | CSSの場合
1
2
3
4
5
6
7
8
9
.search {
  margin: 30px;
}
.search__input {
  font-size: 18px;
}
.search__btn {
  color: red;
}

しかし、SCSSを利用することで、より簡潔に以下のように記述できます。

例 | SCSSの場合
1
2
3
4
5
6
7
8
9
10
11
.search {
  margin: 30px;

  &__input {
    font-size: 18px;
  }

  &__btn {
    color: red;
  }
}

このようにSCSSを使用すると、BEMによる冗長なクラス名も簡潔に管理でき、コーディングの効率が大幅に向上します。

Sassには、SASS記法とSCSS記法の2種類ありますが、本章ではSCSS記法について学習します。

ぴかわかさん
ポイント
  1. SCSSは、Sassの一つの記法(書き方)である
  2. BEMと組み合わせることで、クラス名が長くなる問題を解決し、コーディングをより効率的に行うことができる

SCSSの特徴

SCSS記法は、CSSと同じ書き方を採用しており、CSSに慣れている開発者にとって非常に取り入れやすく、学習コストが低いです。

SCSSの主要な特徴は、.scssというファイル拡張子を持ち、CSSに比べて波括弧{}を使用した入れ子構造(ネスト)が使える点です。このネストを使うことで、HTMLの階層構造をCSS内で直感的に表現し、コードの可読性と保守性を向上させることができます。

以下のHTMLの階層構造を例にしてみましょう。

HTML
1
2
3
4
<ul>
  <li>サンプルテキスト</li>
  <li>サンプルテキスト</li>
</ul>

この例では、ul要素が親要素であり、li要素がその子要素として階層構造を形成しています。このような階層構造の場合、通常のCSSでは、以下のようにulのスタイルとliのスタイルを個別に指定します。

ulの波括弧{}内には、ul自体のスタイルのみが含まれ、子要素であるliのスタイルは別に指定されます。

sample.css | CSS
1
2
3
4
5
6
7
8
ul {
margin: 1em;
}
li { padding-left: 1em; color: red; }

しかし、SCSS記法では、以下のようにulの波括弧{}内にliの子要素を含むネストで記述することができます。ulliの親子関係がコード上で明確になり、より管理しやすくなります。

sample.scss| SCSS
1
2
3
4
5
6
7
8
ul {
margin: 1em; li { padding-left: 1em; color: red; }
}
表のスタイルをSCSS記法でネストしてみましょう

layout.scssファイルにおける表のスタイル指定は、現在以下のようになっています。

app/assets/stylesheets/layout.scss | 変更前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...中略...

table {
  margin: 25px 0;
}

table th {
  background-color: #ffd099;
  padding: 10px 20px;
}

table td {
  background-color: #fff2e2;
  padding: 10px 20px;
}

// ...後略...

この部分をSCSS記法を使用して、以下のように入れ子構造(ネスト)にしてみましょう。

tableタグのスタイル定義内に、thおよびtdタグのスタイル定義をネストして配置し、インデントを施しましょう。これにより、セレクタの先頭にあったtableを繰り返し記述する必要がなくなり、コードが簡潔になります。

app/assets/stylesheets/layout.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...中略...

table {
margin: 25px 0;
th {
background-color: #ffd099;
padding: 10px 20px;
}
td {
background-color: #fff2e2;
padding: 10px 20px;
}
}
// ...後略...
エラーメッセージのスタイルをSCSS記法でネストしてみましょう

エラーメッセージのスタイル指定は、現在以下のようになっています。

app/assets/stylesheets/layout.scss | 変更前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ...中略...

.form__errors {
  padding: 15px;
  margin-bottom: 20px;
  border: 1px solid transparent;
  border-radius: 4px;
  color: #a94442;
  background-color: #f2dede;
  border-color: #ebccd1;
}

.form__errors h3 {
  margin-top: 0;
  color: inherit;
}

.form__errors ul {
  margin: 0;
  padding: 0;
  list-style-type: none;
}

.form__errors li {
  margin-bottom: 10px;
}

// ...後略...

この部分をSCSS記法を使用して、以下のように入れ子構造(ネスト)にしてみましょう。

以下の変更により、セレクタの先頭にあった.form__errorsを繰り返し記述する必要がなくなります。

app/assets/stylesheets/layout.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ...中略...

.form__errors {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
h3 {
margin-top: 0;
color: inherit;
}
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
li {
margin-bottom: 10px;
}
}
// ...後略...
layout.scssを変更した後は、表やエラーメッセージのスタイルが崩れていないかWebブラウザで確認し、問題がなければ次へ進みましょう!
ポイント
  1. SCSSのファイルの拡張子は.scssである
  2. 入れ子構造を用いることで、HTMLの階層をCSS内で直感的に表現できる
  3. 波括弧{}を使用した入れ子構造により、CSSの依存関係をより明確に示せる

セパレーターの親子関係の理解

BEMでは、クラス名を用いてHTMLの構造を表現します。BlockとElementの間を区切る二重アンダースコア__と、Modifierを示す二重ハイフン--を「セパレーター」と呼びます。これらのセパレーターは、クラス名内での関係性を明確にします。

セパレーターを使用することで示される「区切り元」と「区切り先」は、BlockとElementにおいては「親子」の関係に相当します。たとえば、search__inputではsearchが「親的な役割」で、inputが「子的な役割」となります。

HTML
1
2
3
4
<div class="search">
<input type="search" class="search__input"><!-- searchが区切り元、inputが区切り先 -->
<input type="submit" class="search__btn"><!-- Element --> </div>

上記のような親子の関係性では、アンパサンド&を利用します。

アンパサンド

アンパサンド&は、親セレクタを効率的に参照することができます。親要素のクラス名を繰り返し記述することなく、コードを簡潔に保つことが可能になります。

BEMのElementをSCSSで記述する際には、以下のようにします。

BEMのElementをSCSSで記述する場合
1
2
3
4
5
.block {
  &__element { /* &は.blockを参照、.block__elementを生成 */
    // スタイル
  }
}

例えば、.search内でネストされた&__input&__btnの記述では、&は親セレクタである.searchを指します。

sample.scss | SCSSの場合
1
2
3
4
5
6
7
8
9
10
11
.search {
  margin: 30px;

  &__input { /* &は.searchを参照、.search__inputを生成 */
    font-size: 18px;
  }

  &__btn { /* 同様に、.search__btnを生成 */
    color: red;
  }
}

これらはCSSにコンパイルされた際、以下のような形式になります。

コンパイル後のCSS
1
2
3
4
5
6
7
8
9
.search {
  margin: 30px;
}
.search__input {
  font-size: 18px;
}
.search__btn {
  color: red;
}

BEMのデメリットは、クラス名が長くなりCSSで記述する際は冗長になってしまう点でしたが、SCSSのアンパサンド&を使ってネストすることで、親セレクタを参照し、クラス名を短く記述することができます。

ぴっかちゃん

SCSSを使えば、.searchのように同じクラス名を何度も書く必要がなくなり、コードがすっきりして、読みやすくなるよね!

セパレーターを忘れてしまうと、ネストしている&で期待した親子関係が反映されないんだ。SCSSはちゃんとCSSに変換されるけど、意図したスタイルが適用されなくなるかもしれないから、セパレーターの使い方には注意しようね。

ぴかわかさん
ポイント
  1. SCSSのネスト機能を利用することにより、BEMでの長く冗長になりがちなクラス名を短縮し、保守性と可読性の高いスタイルシートを作成できる
  2. アンパサンド&を活用することで、親セレクタの参照が簡略化される

アンパサンドを使って書き換えてみよう

ヘッダー部分をアンパサンドを使用して書き換えましょう

layout.scssファイルにおけるヘッダーのスタイル指定は、現在以下のようになっています。

app/assets/stylesheets/layout.scss | 変更前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...中略...

.header {
  padding: 16px;
  box-shadow: 0 0 15px #e2e6ef;
  background-color: #fff;
}

.header__title {
  color: #525fe1;
  font-size: 28px;
}

// ...後略...

上記の部分は、以下の手順に従って、SCSS記法でネストしてみましょう。

  1. .headerのスタイル定義の末尾にある閉じカッコ}を、.header__titleのスタイル定義の後に移動する
  2. .header__titleのスタイル定義を.headerのスタイル定義の内側にインデントして配置する
  3. .header__titleのセレクタのうち、.headerの部分を&に置き換える

これらの手順により、以下のようなSCSS記法でネストしたスタイル定義が完成します。

app/assets/stylesheets/layout.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...中略...

.header {
padding: 16px;
box-shadow: 0 0 15px #e2e6ef;
background-color: #fff;
&__title {
color: #525fe1;
font-size: 28px;
}
}
// ...後略...
ぴっかちゃん

&__title&って、親セレクタの.headerを指しているんだね!

その通りだよ!これで.headerの中で.header__titleを定義できるんだ。残りの部分も書き換えていこう!

ぴかわかさん
その他の部分もアンパサンドを使用して書き換えましょう

layout.scssを以下のようにアンパサンドを使ってSCSS記法で書き換えてみましょう。変更箇所が複数あるため、コピー&ペーストでの更新作業でも問題ありません。

app/assets/stylesheets/layout.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
body {
  display: flex;
  flex-direction: column;
}

.header {
  padding: 16px;
  box-shadow: 0 0 15px #e2e6ef;
  background-color: #fff;

  &__title {
    color: #525fe1;
    font-size: 28px;
  }
}

.notice {
  padding: 15px;
  margin-bottom: 20px;
  border: 1px solid transparent;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
  border-color: #d6e9c6;
}

.form__errors {
  padding: 15px;
  margin-bottom: 20px;
  border: 1px solid transparent;
  border-radius: 4px;
  color: #a94442;
  background-color: #f2dede;
  border-color: #ebccd1;

  h3 {
    margin-top: 0;
    color: inherit;
  }

  ul {
    margin: 0;
    padding: 0;
    list-style-type: none;
  }

  li {
    margin-bottom: 10px;
  }
}

.main {
flex: 1;
margin-top: 30px;
padding: 0 20px;
&__content {
margin: 0 auto;
width: 66%;
h2 {
font-size: 26px;
}
}
}
.employee-navigation { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } table { margin: 25px 0; th { background-color: #ffd099; padding: 10px 20px; } td { background-color: #fff2e2; padding: 10px 20px; } }
.employee-button {
padding-top: 20px;
margin-bottom: 60px;
&__delete {
display: inline-block;
border-radius: 4px;
padding: 10px 30px;
background-color: #efefef;
text-decoration: none;
color: #333;
}
}
.form {
margin: 25px 0;
&__group {
margin-bottom: 30px;
}
&__submit {
text-align: center;
padding-top: 20px;
font-weight: 700;
margin-bottom: 60px;
}
&__button {
border-radius: 4px;
padding: 10px 30px;
text-align: center;
}
select,
input[type="text"],
input[type="date"] {
width: 100%;
height: 42px;
border: 1px solid #c0c6d6;
border-radius: 2px;
padding: 10px 16px;
margin: 8px 0;
}
}
.footer {
margin-top: 70px;
padding: 6px;
background: #525fe1;
&__text {
color: #fff;
text-align: center;
font-size: 12px;
margin: 0;
}
}
layout.scssを変更した後は、各画面のスタイルが崩れていないかWebブラウザで確認し、問題がなければ次へ進みましょう!

@importディレクティブ

ディレクティブとは、@に続く名前で指定される命令のことを指します。@importディレクティブは、他のスタイルシート(.scssファイル)を現在のファイルにインポートする機能を提供します。

@importディレクティブの使い方
1
2
3
4
5
/* 他のファイルをインポートする */
@import "ファイル名.scss"; 

/* 拡張子は省略可能 */
@import "ファイル名"; 

複数のスタイルシートを分割して管理しやすくなります。CSSにコンパイルされる際には、インポートされたすべてのスタイルが1つのファイルに統合されます。

application.cssファイルをapplication.scssに変更し、SCSSの@importディレクティブを利用してみましょう。

ぴかわかさん

@importディレクティブを使ってみよう

application.cssでは、デフォルトの設定でapp/assets/stylesheetsディレクトリ下のすべてのスタイルシートを読み込んでいます。

application.scssに変更した場合、ファイルのインポートには@importディレクティブの使用が推奨されます。では、その変更を行ってみましょう。

application.cssファイルをapplication.scssに変更してSCSSを利用しましょう

application.cssは、app/assets/stylesheetsディレクトリ内に存在します。

以下のようにファイルの拡張子を.cssから.scssに変更しましょう。ファイル名の変更は、対象のファイルを右クリックし、「Rename」オプションを選択してください。

@importディレクティブを利用してみましょう

application.scssファイルを開いて、以下のようにファイル内を変更しましょう。

app/assets/stylesheets/application.scss | 変更前
1
2
3
4
5
/*
 *= require reset
 *= require_tree .
 *= require_self
 */
app/assets/stylesheets/application.scss | 変更後
1
2
@import 'reset';
@import 'layout';

この変更により、app/assets/stylesheetsディレクトリ内のreset.scsslayout.scssが読み込まれます。reset.scssを先に読み込ませることで、スタイルシートが適用される前に、ブラウザのデフォルトスタイルをリセットすることが可能になります。

最後に、各画面のスタイルが崩れていないかWebブラウザで確認しましょう!

さいごに

この記事を通じて、BEMとSCSSを用いたクリーンなデザインコードの作成方法について理解を深めることができたでしょう。BEMによる構造的なクラス命名とSCSSの機能を利用することで、CSSコードの可読性とメンテナンス性が大幅に向上します。これらの手法は、Webデザインの品質を高めるだけでなく、チームでの作業効率化にも寄与します。

この記事のまとめ

  • BEMによる命名規則は、CSSの可読性と再利用性を向上させる。
  • SCSSはCSSのメンテナンス性を高め、複雑なスタイリングをシンプルに実装可能にする。