すでにメンバーの場合は

無料会員登録

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

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

Pikawakaにログイン

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

RailsのレイアウトとCSS設計を学ぼう

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

前回までの開発で、社員情報一覧画面は何もスタイルを当てていない状態です。

本章では、RailsのCSSの適法方法やレイアウトの仕組み、効率良くコーディングできるBEMとSassを利用したCSS設計を学習しながら、社員情報一覧画面を以下のような見た目に変更していきます。

レイアウトの変更

まずは、RailsでCSSのスタイルを適用する方法を学習します。

RailsはWebアプリケーション開発をすばやく行えるように、さまざまなことがデフォルトで設定されています。CSSもあるディレクトリに配置するだけで、すぐに利用できるよう設定されています。この部分は、レイアウトの仕組みやスタイルシートの読み込みを学習することで理解することができます。

CSSを適用させてみよう

Railsでは、CSSファイルはapp/assets/stylesheets/ディレクトリ内に配置します。

rails generateコマンドでコントローラを生成すると、そのコントローラ用のCSSファイルも自動で生成されます。今回はアプリケーションにsass-railsというgemを入れているので、生成されるファイルの拡張子はcssではなくscss(※1)になります。

employeesコントローラを生成した際には、以下のようにapp/assets/stylesheets/ディレクトリ内にemployees.scssというファイルが生成されています。

社員情報一覧ページのタイトルの文字色を変えてみましょう。

まずはapp/assets/stylesheets/ディレクトリ内にあるemployees.scssを開いて、以下のようにタイトルの文字色を#f44336に指定しましょう。

app/assets/stylesheets/employees.scss
1
2
3
.title {
  color: #f44336;
}

続いて、上記の文字色を社員情報一覧ページのタイトルに適用させてみます。

app/views/employees/ディレクトリ内のindex.html.erbを開いて、以下のハイライト箇所のようにh1要素にclass属性titleを指定しましょう。

app/views/employees/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
<div>
  <% if notice.present? %>
    <p><%= notice %></p>
  <% end %>

  <div>
<h1 class='title'>社員情報一覧</h1>
<%= link_to '社員を作成', '/employees/new' %> </div> <%= render @employees %> </div>

最後にWebブラウザで確認してみます。

ターミナルでrails sコマンドを実行して、Webサーバーを起動しましょう。その後、社員一覧情報の画面にアクセスし、タイトルの文字色が変更されていることを確認しましょう。

このようにスタイルシートを適用させるには、app/assets/stylesheetsディレクトリ内にCSSファイルなどを配置させます。

ぴっかちゃん

employees.scssって外部ファイルだよね。CSSの適用方法で学んだときは、外部ファイルはlink要素で呼び出してスタイルを適用させる必要があったけど、Railsでは違うのかな?

外部CSS

HTMLファイル | link要素の書き方
1
2
3
4
5
6
<!DOCTYPE html>
<html>
  <head>
<link rel="stylesheet" href="CSSファイルの場所">
</head> </html>

外部ファイルのスタイル適用は、Railsでもlink要素での呼び出しが必要だよ。index.html.erbではスタイルシートを読み込んでないように見えるね。これは「レイアウト」という仕組みが大きく関係するよ。

ぴかわかさん

レイアウトの仕組みを確認しよう

ビューはコントローラのアクションの処理結果を受け取り、Webブラウザでレンダリングさせるための「HTMLファイル」を作成して、コントローラに渡します。

このときビューは、個別のテンプレート(index.html.erb)によって作成されたHTMLだけを返しているわけではありません。

ビューの流れ

Railsのデフォルトでは、個別のテンプレートは「アプリケーションで共通のレイアウト」に自動で埋め込まれます。その上で最終的なHTMLが生成されます。つまり、個別のテンプレートとレイアウトを組み合わせたHTMLが生成されます。

共通のレイアウトは、application.html.erbのことです。

application.html.erbを開くと、以下の内容が定義されています。

ハイライト箇所の<%= yield %>に注目してください。デフォルトでは、個別のテンプレートが<%= yield %>に自動で埋め込まれます。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
  <head>
    <title>EmployeeManagement</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
<%= yield %>
</body> </html>

employeesコントローラのindexアクションで呼び出されるindex.html.erbのテンプレートを以下のように定義している場合で考えてみます。

例 | app/views/employees/index.html.erb
1
2
<h1>個別のテンプレート</h1>
<p>レイアウトに自動で埋め込まれます。</p>

上記のテンプレートで定義したものは、以下のようにレイアウトの<%= yield %>に自動で埋め込まれた上で、最終的な出力を生成します。

そして、以下のようにコントローラに生成したHTMLファイルを返します。

このようにRailsではデフォルトで個別のテンプレートには、レイアウトが適用されます。

レイアウトをうまく利用することで、重複コードを避けることができます。例えば、ヘッダーやフッターなど他のページでも共通する部分をapplication.html.erbに記述することで、個別のテンプレートには、ページ固有のコンテンツだけを定義すればよくなります。

<%= yield %>をコメントアウトして、挙動を確認してみましょう。

application.html.erbの<%= yield %>では、コントローラで実行したアクションと同じ名前のビューのファイル(個別のテンプレート)のHTMLが出力されます。<%= yield %>をコメントアウトして、個別のテンプレートが出力されないことを確認してみます。

まずは、application.html.erbを以下のハイライト箇所のように編集しましょう。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
  <head>
    <title>EmployeeManagement</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
<%#= yield %>
<h1>レイアウトテンプレート</h1>
<p>アプリケーションで共通のテンプレートです。</p>
</body> </html>

続いて、Webブラウザで社員情報一覧ページを開きましょう。

社員情報一覧ページを開くと、以下のようにapplication.html.erbで定義したコンテンツだけが出力されていることが確認できます。

社員情報一覧ページのソースも確認してみましょう。

画面上で右クリックします。以下のようにメニューが表示されるので、「ページのソースを表示」をクリックしましょう。

クリックすると、別タブでページが開かれます。

以下のようにbody要素内には、employeesコントローラのindexアクションで呼び出されるindex.html.erbのHTMLは出力されていないことが確認できます。

最後に<%= yield %>のコメントを外して、application.html.erbに個別のテンプレートの内容が展開されるようにしましょう。

application.html.erbを以下のように元に戻しましょう。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
  <head>
    <title>EmployeeManagement</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
<%= yield %>
</body> </html>

社員情報一覧ページを開き、以下のようにindex.html.erbのコンテンツが表示されていることを確認しましょう。

社員情報一覧ページのソースも確認してみましょう。先ほどと同様に画面上で右クリックし、メニューから「ページのソースを表示」を選択します。

ページのソースを表示すると、以下のようにindex.html.erbのコンテンツを表示することができていますね。

このように個別のテンプレートがレイアウトであるapplication.html.erbの<%= yield %>に自動で埋め込まれて、HTMLを展開されることがわかりました。

外部CSSの読み込みを確認しよう

レイアウトの仕組みで学習したように個別のテンプレートは、レイアウトに埋め込まれた上でHTMLを生成します。index.html.erbでは、外部CSSファイルを読み込むことなくemployees.scssのスタイルが適用されているように見えましたね。

実は、レイアウトのhead要素内のstylesheet_link_tagから読み込まれています。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
  <head>
    <title>EmployeeManagement</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html>

stylesheet_link_tagは、外部スタイルシートを読み込むlinkタグを生成します。

上記の場合は、app/assets/stylesheets/application.cssを読み込むことを示しています。

application.cssを開くと、以下の内容が定義されています。

ハイライト箇所のrequire_tree .によって、app/assets/stylesheetsディレクトリ配下にある全てのファイルが読み込まれるように設定されます。

app/assets/stylesheets/application.css
1
2
3
4
5
6
/*
 # 中略 #
 *
*= require_tree .
*= require_self */

次の行にあるrequire_selfapplication.css自身も含めるように設定します。

このようにレイアウトから読み込まれるapplication.cssrequire_tree .によって、app/assets/stylesheetsディレクトリ配下のスタイルシートが読み込まれます。

CSS設計

次は、CSS設計手法の「BEM」やBEMと親和性の高い「Sass」を学習します。

BEM

BEMとは、Block(かたまり)・Element(要素)・Modifier(修飾)の頭文字をとったものです。厳格なクラス名の命名ルールが特徴的なCSS設計方法の1つです。

命名規則
1
block__element--modifier

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

以下のようにBlock(かたまり)を構成するのがElement(要素)です。

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

Modifier(修飾)は、BlockとElementのスタイル状態を修飾します。

HTML | Block(Element)と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で解決することができます。

ポイント
  1. BEMとは、厳格なクラス名の命名ルールが特徴的なCSS設計方法の1つである
  2. BEMは、Block(かたまり)・Element(要素)・Modifier(修飾)の略
  3. 長期的なメンテナンス性が高くなったり、開発スピードを上げることができる

Block(かたまり)

Webページは、ヘッダー、フッダー、ナビゲーション、サイドバー、メインなどのパーツで構成されています。このパーツにあたる部分がBlock(かたまり)になります。

Header blockの中にあるNav blockのように、Blockは他のBlockを含めることができます。

bem_1

検索フォームで確認してみます。

検索フォームは、Webページを構成するパーツに当たる部分です。この部分はBlockとして捉えることができますね。

Element(要素)

検索フォームには、入力欄や送信ボタンの要素がありますが、Blockだけを指定する場合は、以下のように外側のdiv要素に対して、searchというクラスを付与します。

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

それでは、アプリケーションにもBlockでスタイルを指定してみます!

ぴかわかさん
ポイント
  1. Webページは、ヘッダー、フッダー、メインなどのパースで構成されているが、BEMではパーツにあたる部分がBlock(かたまり)になる
  2. Blockは、他のBlockを含めることができる
Blockのスタイルを指定してみよう

application.html.erbのbody要素内に文書の主要な内容を表すmain要素を追加します。そのmain要素に対して、Blockのクラス名を付与します。クラス名は、社員情報を表すemployeeとします。

application.html.erbを開いて、ハイライト箇所のように編集しましょう。
app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
  <head>
    <title>EmployeeManagement</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
<main class="employee">
<%= yield %>
</main>
</body> </html>

続いて、スタイルを指定します。

employees.scssを開いて、以下のスタイルを指定しましょう。
app/assets/stylesheets/employees.scss
1
2
3
4
5
6
7
8
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;
}

employees.scssには、.titleに対して文字色を指定していましたが、そちらは消しておきましょう。以下のように.employeeに対してのスタイル指定だけになります。

employeeクラスにスタイルを指定したら、ブラウザを再読み込みしてください。以下のように再読み込みしても、見た目の変化が少しわかりづらいですね。

デベロッパーツール(開発者用の検証ツール)で確認してみます。

デベロッパーツールを起動して、スタイルが適用されているか確認しましょう。

画面上で右クリックし、メニューの中から「検証」をクリックして、デベロッパーツールを起動してください。main要素にemployeeクラスが付与されて、以下のようにスタイルが適用されていることを確認しましょう。

Element(要素)

Elementは、Blockを構成する要素です。ElementはBlockに属しているので、必ずBlockのクラス名を含めます。BlockとElementは、二重アンダースコア(__)で区切ります。

先ほどの検索フォームで確認してみます。

検索フォームの入力欄と送信ボタンは、「Search block」を構成する要素(Element)になります。

Element(要素)

検索フォームをBlockとElementで指定する場合、以下のように記述することができます。

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

2行目のElementのクラス名は、search__inputです。Blockのsearchの後に二重アンダースコア(__)でinputを指定していますね。

他にもNav blockのElementのように、ElementはBlock内で繰り返し使うこともできます。

bem_3

ポイント
  1. Elementとは、Blockを構成する要素のこと
  2. ElementはBlockに属しているので、必ずBlockのクラス名を含める
  3. BlockとElementは、二重アンダースコア(__)で区切る
Elementのスタイルを指定してみよう

社員情報一覧のElementのスタイルを指定します。

先ほどは<%= yield %>の外側のmain要素をBlockにして、employeeというクラスを付与しましたね。

app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
  <head>
  <!-- 中略 -->
  </head>

  <body>
<main class="employee">
<%= yield %>
</main>
</body> </html>

レイアウトの仕組みでも学習したように<%= yield %>には、個別のテンプレートが埋め込まれます。社員情報一覧のElementは、Blockのemployeeに属すのでクラス名はemployee__Elementになります。

index.html.erbを開いて、ハイライト箇所のように編集しましょう。
app/views/employees/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
<div class="employee__index">
<% if notice.present? %> <p><%= notice %></p> <% end %>
<div class="employee__index__body">
<h1 class="employee__index__body-title">社員情報一覧</h1>
<%= link_to '社員を作成', '/employees/new', class: "employee__button" %>
</div> <%= render @employees %> </div>

link_toでクラス名を付与する場合、class: "クラス名"と指定します。

h1要素に付与したクラス名はemployee__index__body-titleですが、body-titleは2つの単語で表しています。このようにBlockやElementを2つ以上の単語で表す場合は「単語-単語」のように、区切り文字にハイフンを使用します。

employees.scssを開いて、以下のハイライト箇所のスタイルを指定しましょう。
app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;
}

.employee__index {
width: 100%;
}
.employee__index__body {
display: flex;
justify-content: space-between;
align-items: center;
}
.employee__index__body-title {
font-weight: 700;
font-size: 36px;
line-height: 40px;
margin: 0;
}
.employee__button {
display: inline-block;
padding: 12px 20px;
font-weight: 700;
border-radius: 8px;
text-decoration: inherit;
color: #000;
font-size: 16px;
}

employees.scssを編集したら、ブラウザを再読み込みしてください。以下のように見た目が少し変わりましたね。

社員情報一覧画面で社員の情報が1人ずつ表示されている箇所は、index.html.erbで呼び出している部分テンプレートの_employee.html.erbです。

部分テンプレートのElementも指定してみましょう。

_employee.html.erbを開いて、以下のハイライト箇所のように編集しましょう。

app/views/employees/_employee.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="employee__list">
<p class="employee__list__item">
<strong class="task__list__item-label">Name:</strong>
<%= employee.name %> </p>
<p class="employee__list__item">
<strong class="task__list__item-label">Birthday:</strong>
<%= employee.birthday %> </p> <p> <strong>Department:</strong> <%= employee.department.name %> </p>
<%= link_to '社員の詳細情報を見る', employee_path(employee), class: "employee__button" %>
<%= link_to '社員を編集する', edit_employee_path(employee), class: "employee__button" %>
<hr> </div>

続いて、employees.scssに上記で付与したクラスのスタイルを指定します。

employees.scssを開いて、以下のハイライト箇所を追加しましょう。

app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;
}

.employee__index {
  width: 100%;
}

.employee__index__body {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.employee__index__body-title {
  font-weight: 700;
  font-size: 36px;
  line-height: 40px;
  margin: 0;
}

.employee__list__item {
margin: 20px 0;
}
.employee__list__item-label {
display: block;
font-weight: 700;
margin-bottom: 4px;
}
.employee__button { display: inline-block; padding: 12px 20px; font-weight: 700; border-radius: 8px; text-decoration: inherit; color: #000; font-size: 16px; }

Webブラウザを再読み込みすると、以下のように見た目が変わります。

Modifier(修飾)

既存のBlockやElementに対して、一部見た目や状態を変えたい場合にModifier(修飾)を使います。

bem_4

Modifierは、「Blockに対して使うModifier」と「Elementに対して使うModifier」があります。BlockやElementの後にハイフン2つで区切って定義します。

Modifierの定義
1
2
3
4
5
<!-- Blockに対して修飾 -->
Block--Modifier

<!-- Elementに対して修飾 -->
Block__Element--Modifier

社員情報一覧画面のボタンは、employee__buttonクラスが付与されています。

employees.scss
1
2
3
4
5
6
7
8
9
10
// 中略
.employee__button {
  display: inline-block;
  padding: 12px 20px;
  font-weight: 700;
  border-radius: 8px;
  text-decoration: inherit;
  color: #000;
  font-size: 16px;
}

3つとも同じスタイルだと分かりづらいので、Modifierで一部見た目を変えてみます。

「社員を作成」ボタンの一部見た目を変更してみましょう。

Modifierは、既存のBlockやElementに対して、一部見た目や状態を変えたい場合に使用します。「社員を作成」ボタンの文字色と背景色だけを変更してみます。

まずはindex.html.erbを開いて、ハイライト箇所のクラス名をemployee__button--blueに変更しましょう。

app/views/employees/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
<div class="employee__index">
  <% if notice.present? %>
    <p><%= notice %></p>
  <% end %>

  <div class="employee__index__body">
    <h1 class="employee__index__body-title">社員情報一覧</h1>
<%= link_to '社員を作成', '/employees/new', class: "employee__button--blue" %>
</div> <%= render @employees %> </div>

続いてemployees.scssを開いて、以下のハイライト箇所のように編集しましょう。

employees.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 中略
.employee__list__item-label {
  display: block;
  font-weight: 700;
  margin-bottom: 4px;
}

.employee__button,
.employee__button--blue {
display: inline-block; padding: 12px 20px; font-weight: 700; border-radius: 8px; text-decoration: inherit; color: #000; font-size: 16px; }
.employee__button--blue {
color: white;
background-color: #2563EB;
}

最後にブラウザを再読み込みさせて、以下のように「社員を作成」のボタンだけが一部見た目が変更されていることを確認しましょう。

他の2つのボタンも変更してみましょう。

_employee.html.erbを開いて、以下のハイライト箇所のように編集しましょう。

app/views/employees/_employee.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="employee__list">
  <p class="employee__list__item">
    <strong class="task__list__item-label">Name:</strong>
    <%= employee.name %>
  </p>

  <p class="employee__list__item">
    <strong class="task__list__item-label">Birthday:</strong>
    <%= employee.birthday %>
  </p>

  <p>
    <strong>Department:</strong>
    <%= employee.department.name %>
  </p>
<%= link_to '社員の詳細情報を見る', employee_path(employee), class: "employee__button--gray" %>
<%= link_to '社員を編集する', edit_employee_path(employee), class: "employee__button--gray" %>
<hr> </div>

employees.scssを開いて、以下のハイライト箇所を追加しましょう。

app/assets/stylesheets/employees.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//中略
.employee__button,
.employee__button--blue,
.employee__button--gray {
display: inline-block; padding: 12px 20px; font-weight: 700; border-radius: 8px; text-decoration: inherit; color: #000; font-size: 16px; } .employee__button--blue { color: white; background-color: #2563EB; }
.employee__button--gray {
background-color: #F3F4F6;
}

最後にブラウザを再読み込みさせて、以下のように「社員を作成」ではないボタンの見た目が変更されていることを確認しましょう。

最終的なemployees.scssの内容を確認しましょう。
app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;
}

.employee__index {
  width: 100%;
}

.employee__index__body {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.employee__index__body-title {
  font-weight: 700;
  font-size: 36px;
  line-height: 40px;
  margin: 0;
}

.employee__list__item {
  margin: 20px 0;
}

.employee__list__item-label {
  display: block;
  font-weight: 700;
  margin-bottom: 4px;
}

.employee__button,
.employee__button--blue,
.employee__button--gray {
  display: inline-block;
  padding: 12px 20px;
  font-weight: 700;
  border-radius: 8px;
  text-decoration: inherit;
  color: #000;
  font-size: 16px;
}

.employee__button--blue {
  color: white;
  background-color: #2563EB;
}

.employee__button--gray {
  background-color: #F3F4F6;
}
ポイント
  1. Modifier(修飾)は、既存のBlockやElementに対して、一部見た目や状態を変えたい場合に使用する
  2. BlockやElementの後にハイフン2つで区切って定義する

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

ぴかわかさん

SCSS

SCSSは、Sassの記法の1つのです。Sassとは、CSSを拡張したメタ言語(言語を定義する為の言語)のことです。

BEMのデメリットは、クラス名が長くなりCSSで記述する際は冗長になってしまう点でしたが、BEMと親和性の高いSassを利用することで、CSSよりも非常に効率良くコーディングすることができます。

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

  &__input {
    font-size: 18px;
  }

  &__btn {
    color: red;
  }
}

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

SCSS記法

SCSS記法は、スタイルの書き方がCSSと変わらないので、元々CSSを書いていた方はSASS記法よりも入りやすいです。

SCSSはCSSと見た目は似ていますが、波括弧{}を入れ子にしている箇所が異なります。

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

上記のHTMLはulを親要素、liを小要素とした階層になります。

このような階層構造の場合、CSSでは親子関係なく、以下のハイライト箇所のようにulの波括弧{}内にはulのスタイルだけが指定されます。子要素のliは含めません。

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

しかし、SCSS記法で記述する場合は、ulの波括弧{}の中にliの子要素を含めた入れ子構造(ネスト)にすることで、依存関係を示すことができます。

例 | SCSSの書き方
1
2
3
4
5
6
7
8
ul {
margin: 1em; li { padding-left: 1em; color: red; }
}
ポイント
  1. SCSSのファイルの拡張子は.scssである
  2. SCSS記法は、入れ子を主とした記法である
  3. 波括弧{}を使い入れ子構造にして、CSSの依存関係を示す

セパレーターの親子関係

BEMでは、Block、Element、Modifierに対してセパレーターを使って区切っていました。この「区切り元」と「区切り先」はそれぞれ「親」と「子」の関係になります。

以下の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>

この親子関係をSassのアンパサンド()と呼ばれるものを利用することで、効率的に記述できるようになります。

アンパサンド

SCSS記法では、アンパサンドと呼ばれる&を使ってネストすると、親セレクタを参照することができます。ネストしたの後にセパレーターを忘れてしまうと、親子関係とみなされず、CSSが上手くコンパイルされないので注意してください。

以下の場合、searchを参照しています。

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

  &__input { /* &はsearchを参照するので search__inputになる */
    font-size: 18px;
  }

  &__btn { /* &はsearchを参照するので 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と書く必要もなく、記述量が減り、見た目もわかりやすくなるね!

CSSをSCSSに書き換えてみよう

employees.scssに記述されるCSSをSCSSに書き換えてみましょう。

.employee{ }の中に.employee__index以下を含めて入れ子構造にしましょう。

employees.scssで指定されるクラス名は、1行目の.employee以外は、全て.employeeに属すElementやModifierです。Blockの中にネストさせて、&で参照させることが可能です。

まずは、8行目にある.employeeの閉じ括弧}を以下のハイライトのように最後に置いて、入れ子構造にしましょう。

app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;

  .employee__index {
    width: 100%;
  }

  .employee__index__body {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .employee__index__body-title {
    font-weight: 700;
    font-size: 36px;
    line-height: 40px;
    margin: 0;
  }

  .employee__list__item {
    margin: 20px 0;
  }

  .employee__list__item-label {
    display: block;
    font-weight: 700;
    margin-bottom: 4px;
  }

  .employee__button,
  .employee__button--blue,
  .employee__button--gray {
    display: inline-block;
    padding: 12px 20px;
    font-weight: 700;
    border-radius: 8px;
    text-decoration: inherit;
    color: #000;
    font-size: 16px;
  }

  .employee__button--blue {
    color: white;
    background-color: #2563EB;
  }

  .employee__button--gray {
    background-color: #F3F4F6;
  }
}

上記のように.employee__index以下は、インデントを「半角スペース2つ分」入れます。インデントは、エディターの右下にある設定で調整することができます。

以下のように「Spaces: 2」であれば、特に設定は必要ありません。

上記以外の方は右下の設定箇所をクリックして、以下のように「Spaces: 2」になるように設定しておきましょう。

あとは動画のように最終行の閉じ括弧を含めない.employee__index以下を全て選択し、tabキーを押して「半角スペース2つ分」のインデントを入れるだけです。

ネストする「.employee」の部分を全てアンパサンド&に置き換えましょう。

.employee{}の中に含むクラス名の.employeeの部分を&に置き換えましょう。

.employee__indexであれば&__index.employee__index__bodyであれば&__index__bodyのように置き換えます。

app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;

&__index {
width: 100%; }
&__index__body {
display: flex; justify-content: space-between; align-items: center; }
&__index__body-title {
font-weight: 700; font-size: 36px; line-height: 40px; margin: 0; }
&__list__item {
margin: 20px 0; }
&__list__item-label {
display: block; font-weight: 700; margin-bottom: 4px; }
&__button,
&__button--blue,
&__button--gray {
display: inline-block; padding: 12px 20px; font-weight: 700; border-radius: 8px; text-decoration: inherit; color: #000; font-size: 16px; }
&__button--blue {
color: white; background-color: #2563EB; }
&__button--gray {
background-color: #F3F4F6; } }
クラス名が重複する部分は、セパレーターの親の{}の中に入れてネストさせましょう。

まずは、以下のハイライト箇所に注目してください。

__indexという部分が重複していますね。&__index { }の中に&__index__body { }&__index__body-title { }を入れてネストさせましょう。

app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;

&__index {
width: 100%; }
&__index__body {
display: flex; justify-content: space-between; align-items: center; }
&__index__body-title {
font-weight: 700; font-size: 36px; line-height: 40px; margin: 0; } // 中略 }
app/assets/stylesheets/employees.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.employee {
  display: flex;
  // 中略
  &__index {
    width: 100%;

&__index__body {
display: flex;
justify-content: space-between;
align-items: center;
}
&__index__body-title {
font-weight: 700;
font-size: 36px;
line-height: 40px;
margin: 0;
}
} // 中略 }

上記の変更によって&__index__body { }&__index__body-title { }が同じ階層になりましたが、2つのクラス名は__index__bodyの箇所が重複しているので、さらにネストできそうです。

以下のように&__index__body { }の中に&__index__body-title { }を入れましょう。

app/assets/stylesheets/employees.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.employee {
  display: flex;
  // 中略
  &__index {
    width: 100%;

    &__index__body {
      display: flex;
      justify-content: space-between;
      align-items: center;

&__index__body-title {
font-weight: 700;
font-size: 36px;
line-height: 40px;
margin: 0;
}
} } // 中略 }

そして、&__list__item{ }&__list__item-label{ }__list__itemが重複していますね。

app/assets/stylesheets/employees.scss | 重複箇所を確認する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.employee {
  display: flex;
  // 中略
&__list__item {
margin: 20px 0; }
&__list__item-label {
display: block; font-weight: 700; margin-bottom: 4px; } // 中略 }

以下のように&__list__item{ }の中に&__list__item-label{ }を入れて、ネストさせましょう。

app/assets/stylesheets/employees.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.employee {
  display: flex;
  // 中略
  &__list__item {
    margin: 20px 0;

&__list__item-label {
display: block;
font-weight: 700;
margin-bottom: 4px;
}
} // 中略 }

以下のemployees.scssのように、重複箇所が全てネストされていることを確認しましょう。&__button以降は、特に変更していません。

app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;

  &__index {
    width: 100%;

    &__index__body {
      display: flex;
      justify-content: space-between;
      align-items: center;

      &__index__body-title {
        font-weight: 700;
        font-size: 36px;
        line-height: 40px;
        margin: 0;
      }
    }
  }

  &__list__item {
    margin: 20px 0;

    &__list__item-label {
      display: block;
      font-weight: 700;
      margin-bottom: 4px;
    }
  }

  &__button,
  &__button--blue,
  &__button--gray {
    display: inline-block;
    padding: 12px 20px;
    font-weight: 700;
    border-radius: 8px;
    text-decoration: inherit;
    color: #000;
    font-size: 16px;
  }

  &__button--blue {
    color: white;
    background-color: #2563EB;
  }

  &__button--gray {
    background-color: #F3F4F6;
  }
}
親のクラス名の部分を全てアンパサンド&に置き換えましょう。

まずは、&__index { }の中に含まれるクラス名を変更していきます。

app/assets/stylesheets/employees.scss | 変更前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.employee {
  //中略
  &__index {
    width: 100%;

&__index__body {
display: flex; justify-content: space-between; align-items: center;
&__index__body-title {
font-weight: 700; font-size: 36px; line-height: 40px; margin: 0; } } } //中略 }

上記のハイライト箇所を以下のように変更しましょう。

app/assets/stylesheets/employees.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.employee {
  //中略
  &__index {
    width: 100%;

&__body { /* &は__indexを参照するので__index__bodyになる */
display: flex; justify-content: space-between; align-items: center;
&-title { /* &は__index__bodyを参照するので__index__body-titleになる */
font-weight: 700; font-size: 36px; line-height: 40px; margin: 0; } } } //中略 }

続いて、&__list__item { }の中に含まれるクラス名を変更していきます。

app/assets/stylesheets/employees.scss | 変更前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.employee {
  display: flex;
  // 中略
  &__list__item {
    margin: 20px 0;

&__list__item-label {
display: block; font-weight: 700; margin-bottom: 4px; } } // 中略 }

上記のハイライト箇所を以下のように変更しましょう。

app/assets/stylesheets/employees.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.employee {
  display: flex;
  // 中略
  &__list__item {
    margin: 20px 0;

&-label { /* &は__list__itemを参照するので__list__item-labelになる */
display: block; font-weight: 700; margin-bottom: 4px; } } // 中略 }

employees.scssを編集したら、ブラウザを再読み込みしてください。CSSからSCSSに書き換えても、社員情報一覧画面のスタイルが正常に適用されていることを確認しましょう。

最終的なemployees.scssの内容を確認しましょう。

CSSからSCSSに書き換える前は、以下のようにBEMのクラス名が冗長で重複するクラス名の部分を繰り返し記述する必要がありましたね。

app/assets/stylesheets/employees.scss | 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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;
}

.employee__index {
  width: 100%;
}

.employee__index__body {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.employee__index__body-title {
  font-weight: 700;
  font-size: 36px;
  line-height: 40px;
  margin: 0;
}

.employee__list__item {
  margin: 20px 0;
}

.employee__list__item-label {
  display: block;
  font-weight: 700;
  margin-bottom: 4px;
}

.employee__button,
.employee__button--blue,
.employee__button--gray {
  display: inline-block;
  padding: 12px 20px;
  font-weight: 700;
  border-radius: 8px;
  text-decoration: inherit;
  color: #000;
  font-size: 16px;
}

.employee__button--blue {
  color: white;
  background-color: #2563EB;
}

.employee__button--gray {
  background-color: #F3F4F6;
}

SCSSに書き換えたことで、以下のようにクラス名の記述量が減り、見た目もわかりやすくなりました。

app/assets/stylesheets/employees.scss | 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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;

  &__index {
    width: 100%;

    &__body {
      display: flex;
      justify-content: space-between;
      align-items: center;

      &-title {
        font-weight: 700;
        font-size: 36px;
        line-height: 40px;
        margin: 0;
      }
    }
  }

  &__list__item {
    margin: 20px 0;

    &-label {
      display: block;
      font-weight: 700;
      margin-bottom: 4px;
    }
  }

  &__button,
  &__button--blue,
  &__button--gray {
    display: inline-block;
    padding: 12px 20px;
    font-weight: 700;
    border-radius: 8px;
    text-decoration: inherit;
    color: #000;
    font-size: 16px;
  }

  &__button--blue {
    color: white;
    background-color: #2563EB;
  }

  &__button--gray {
    background-color: #F3F4F6;
  }
}

このようにBEMと親和性の高いSass(SCSS)を利用することで、CSSよりも非常に効率良くコーディングすることができます。

SCSSの他の機能

SCSSでは、他にも変数演算関数ディレクティブを使用することができます。

本章では、SCSSの代表的な2つのディレクティブである「@extendディレクティブ」と「@importディレクティブ」について学習します。

  1. @extendディレクティブ - 定義済みのスタイルを継承する
  2. @importディレクティブ - 外部のスタイルシートを読み込む

ディレクティブとは@名前で指定することのできる命令のことです。

ぴかわかさん
@extendディレクティブ

@extendディレクティブを利用することで、定義済みのスタイルを他のクラスに継承させることができます。

以下のように.sampleクラスのスタイル定義の中で@extend ディレクティブを使用すると、指定したセレクタに設定されているスタイル定義を、.sampleクラスに継承させることができます。セレクタ名には、クラス名などを引用符で囲まずに指定します。

@extendディレクティブの使い方
1
2
3
.sample {
  @extend <セレクタ名>;
}

例えば、.base-contentのスタイルを.contentに継承させる場合は、以下のように記述します。

SCSS | .base-contentのスタイルを継承する場合
1
2
3
4
5
6
7
8
9
10
11
.base-content {
  border: 1px solid grey;
  font-size: 20px;
  padding: 20px;
  width: 200px;
}

.content {
  @extend .base-content; /* .base-contentを継承する */
  border-color: red; /* 一部スタイルを変更 */
}

上記がCSSにコンパイルされると、以下のように同じプロパティを持つスタイルはまとめられます。そして.contentに定義したborder-color: redは個別に出力されます。

CSSコンパイル後
1
2
3
4
5
6
7
8
9
10
11
.base-content, .content { /*同じスタイルはまとめられる*/
  border: 1px solid grey;
  font-size: 20px;
  padding: 20px;
  width: 200px;
}

/*独自で定義したスタイルは個別に記述される*/
.content { 
  border-color: red;
}

@extendディレクティブを利用することで、同じプロパティをまとめてくれるので、余計な重複コードを出力してしまうという心配がなくなります。またベースのスタイルを継承した上で一部スタイルを変更させることができます。

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

&__button--blue{ }&__button--gray{ }の中に@extendディレクティブを利用して、&__button { }のスタイルを継承できるようにしていきます。

app/assets/stylesheets/employees.scss | @extendディレクティブを利用する箇所を確認する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.employee {
  // 中略
  &__button,
  &__button--blue,
  &__button--gray {
display: inline-block;
padding: 12px 20px;
font-weight: 700;
border-radius: 8px;
text-decoration: inherit;
color: #000;
font-size: 16px;
}
&__button--blue {
color: white; background-color: #2563EB; }
&__button--gray {
background-color: #F3F4F6; } }

上記を以下のように変更しましょう。@extendディレクティブで指定するセレクタは、&__buttonのコンパイル後のクラス名の.employee__buttonです。

app/assets/stylesheets/employees.scss | 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.employee {
  // 中略
&__button { /* コンパイル後のクラス名は.employee__buttonになる */
display: inline-block; padding: 12px 20px; font-weight: 700; border-radius: 8px; text-decoration: inherit; color: #000; font-size: 16px; } &__button--blue {
@extend .employee__button; /* .employee__buttonを継承する */
color: white; background-color: #2563EB; } &__button--gray {
@extend .employee__button; /* .employee__buttonを継承する */
background-color: #F3F4F6; } }

@extendディレクティブを利用して&__button { }のスタイルを&__button--blue&__button--grayに継承させることができました。上記のようにコードを変更したことで、クラス名が重複する部分(__button)を&で記述できるようになります。

ネストと&を利用して、クラス名が重複する部分をなくしましょう。

&__button { }の中に&__button--blue { }&__button--gray { }を入れて、以下のように&でクラス名を&--blue&--grayに変更しましょう。

app/assets/stylesheets/employees.scss | アンパサンド&を使ってネストする
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.employee {
  // 中略
    &__button {
    display: inline-block;
    padding: 12px 20px;
    font-weight: 700;
    border-radius: 8px;
    text-decoration: inherit;
    color: #000;
    font-size: 16px;

&--blue {
@extend .employee__button; color: white; background-color: #2563EB; }
&--gray {
@extend .employee__button; background-color: #F3F4F6; }
}
}

アンパサンド&を使ってネストすると、親セレクタを参照し、クラス名が重複する部分をスッキリと記述することができます。

最終的なemployees.scssの内容を確認しましょう。
app/assets/stylesheets/employees.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
.employee {
  display: flex;
  margin-left: auto;
  margin-right: auto;
  margin-top: 112px;
  max-width: 90%;
  padding: 0 20px;

  &__index {
    width: 100%;

    &__body {
      display: flex;
      justify-content: space-between;
      align-items: center;

      &-title {
        font-weight: 700;
        font-size: 36px;
        line-height: 40px;
        margin: 0;
      }
    }
  }

  &__list__item {
    margin: 20px 0;

    &-label {
      display: block;
      font-weight: 700;
      margin-bottom: 4px;
    }
  }

  &__button {
    display: inline-block;
    padding: 12px 20px;
    font-weight: 700;
    border-radius: 8px;
    text-decoration: inherit;
    color: #000;
    font-size: 16px;

    &--blue {
      @extend .employee__button;
      color: white;
      background-color: #2563EB;
    }

    &--gray {
      @extend .employee__button;
      background-color: #F3F4F6;
    }
  }
}
@importディレクティブ

@importディレクティブは、外部スタイルシート(.scssの拡張子のファイル)をインポートする機能です。CSSにコンパイルされると、1つのファイルとして書き出されます。

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

/* 拡張子は省略可能なので、下記でも良い*/
@import "ファイル名"; 
@importディレクティブを利用してみましょう。

application.cssではrequire_tree .によって、app/assets/stylesheetsディレクトリ配下にある全てのファイルが読み込まれるように設定されていましたね。

app/assets/stylesheets/application.css
1
2
3
4
5
6
/*
 # 中略 #
 *
*= require_tree .
*= require_self */

require_tree .を利用せずに、@importディレクティブでapplication.cssにemployees.scssをインポートしてみます。以下のように編集してください。

app/assets/stylesheets/application.css | 変更後
1
@import './employees';

以下のようにapplication.cssに元々記述されていたコードは、全て削除して@import './employees';を追加しましょう。

application.cssを編集したら、ブラウザを再読み込みしてください。以下のように社員情報一覧画面は、employees.scssのスタイルが適用されていないことが確認できます。

application.cssでemployees.scssが正常にインポートされていません。どこが間違えているか分かりますか。

app/assets/stylesheets/application.css | 正常にインポートされない
1
@import './employees';

@importディレクティブは、CSSではなくSass(SCSS)の機能です。そのため、ファイルの拡張子をapplication.cssからapplication.scssに変更する必要があります。

以下のようにファイル名を変更しましょう。

ファイル名の拡張子を.scssに変更したら、再度ブラウザを再読み込みして、以下のように社員情報一覧画面にスタイルが適用されていることを確認しましょう。

ここまでの学習したBEMとSCSSの知識を活かして、社員情報一覧画面以外のページもスタイル定義していきましょう。

ぴかわかさん

詳細画面の見た目を変えてみよう

詳細画面の見た目をBEMとSCSSで定義していきます。

まずは、詳細画面にアクセスしてみましょう。詳細画面にアクセスすると、以下の緑枠で囲う部分はすでに見た目が整っていますね。

これはindex.html.erbshow.html.erbが同じ部分テンプレート(_employee.html.erb)を呼び出しているからです。

社員情報一覧画面の見た目を作成する際に、_employee.html.erbには以下のようにBEMでクラスを指定しましたね。そのクラスに対しても、スタイルは定義済みです。

app/views/employees/_employee.html.erb | 社員情報一覧画面の見た目を作るときに一緒に変更した内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="employee__list">
  <p class="employee__list__item">
    <strong class="task__list__item-label">Name:</strong>
    <%= employee.name %>
  </p>

  <p class="employee__list__item">
    <strong class="task__list__item-label">Birthday:</strong>
    <%= employee.birthday %>
  </p>

  <p>
    <strong>Department:</strong>
    <%= employee.department.name %>
  </p>
  <%= link_to '社員の詳細情報を見る', employee_path(employee), class: "employee__button" %>
  <%= link_to '社員を編集する', edit_employee_path(employee), class: "employee__button" %>
  <hr>
</div>

部分テンプレート以外のshow.html.erbの箇所をBEMで指定していきます。

show.html.erbを開いて、BEMでクラス名を指定しましょう。

以下のハイライト箇所のように、BEMでクラス名を指定しましょう。

app/views/employees/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="employee__show">
<div class="employee__show__body">
<% if notice.present? %> <p><%= notice %></p> <% end %> <%= render @employee %>
<%= link_to '社員一覧画面に戻る', '/employees', class: "employee__button--gray" %>
<div>
<%= button_to '社員を削除する', employee_path(@employee), method: :delete, class: "employee__button--gray" %>
</div> </div> </div>

link_toの箇所に指定したクラス名のスタイルは、すでに社員情報一覧画面を作成した際に定義されているので、クラスを付与しただけでスタイルが適用されます。

Webブラウザを再読み込みすると、以下のように見た目が変わります。

employees.scssを開いて、SCSSでスタイルを定義しましょう。

以下のCSSをSCSSに書き換えて、employees.scssでスタイルを定義してみましょう。SCSSの書き換えは、CSSをSCSSに書き換えを参考にしてください。

CSS
1
2
3
4
5
6
7
8
9
10
11
.employee__show {
  display: flex;
  width: 66%;
  margin-left: auto;
  margin-right: auto;
}

.employee__show__body {
  margin-left: auto;
  margin-right: auto;
}

上記のCSSをSCSSに書き換えて、employees.scssで定義することができれば、詳細画面は以下のような見た目になります。

employees.scssを編集したら、以下の「解答をみる」をクリックして、SCSSの書き方があっているかを確認しましょう。

解答をみる
答え
app/assets/stylesheets/employees.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
.employee {
  //中略
  &__index {
    width: 100%;

    &__body {
      display: flex;
      justify-content: space-between;
      align-items: center;

      &-title {
        font-weight: 700;
        font-size: 36px;
        line-height: 40px;
        margin: 0;
      }
    }
  }

&__show {
display: flex;
width: 66%;
margin-left: auto;
margin-right: auto;
&__body {
margin-left: auto;
margin-right: auto;
}
}
&__list__item { margin: 20px 0; &-label { display: block; font-weight: 700; margin-bottom: 4px; } } //中略 }
style属性を利用して、ボタンを横並びにしてみましょう。

以下のように1箇所だけスタイルが異なりますね。これは、ユーザーエージェントスタイルシートの影響です。style属性を利用して、ボタンを横並びにしてみます。

Railsでは外部スタイルシートを呼び出す以外にも、CSSの適用方法で学習したようなstyle要素やstyle属性を利用することができます。style属性では、要素内にstyle属性を追加して単一の要素のみスタイルを適用できます。

以下のハイライト箇所のようにshow.html.erbのdiv要素にstyle属性を追加しましょう。

app/views/employees/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="employee__show">
  <div class="employee__show__body">
    <% if notice.present? %>
      <p><%= notice %></p>
    <% end %>

    <%= render @employee %>

    <%= link_to '社員一覧画面に戻る', '/employees', class: "employee__button--gray" %>
<div style="display: inline-block; margin-left: 2px;">
<%= button_to '社員を削除する', employee_path(@employee), method: :delete, class: "employee__button--gray" %> </div> </div> </div>

Webブラウザを再読み込みすると、以下のように見た目が変わります。

新規投稿画面の見た目を変えてみよう

新規投稿画面の見た目をBEMとSCSSで定義していきます。

まずは、新規投稿画面にアクセスしてみましょう。以下のようにユーザーエージェントスタイルシートだけが適用されている状態です。

new.html.erbを開いて、BEMでクラス名を指定しましょう。
app/views/employees/new.html.erb
1
2
3
4
5
<div class="employee__new">
<h1 class="employee__new-title">社員を新規作成</h1>
<%= render "form", employee: @employee %> </div>
_form.html.erbを開いて、BEMでクラス名を指定しましょう。

new.html.erbでは、部分テンプレートの_form.html.erbを呼び出しています。

以下のハイライト箇所のように_form.html.erbにBEMでクラスを付与しましょう。

form.collection_selectにはクラス名だけではなく、{prompt: "選択してください"}も追加しましょう。

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, class: "employee__new__form") do |form| %>
<% if @employee.errors.any? %> <div> <ul> <% @employee.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %>
<div class="employee__new__form__item">
<%= form.label :name %>
<%= form.text_field :name, class: "employee__new__form__item-input" %>
</div>
<div class="employee__new__form__item">
<%= form.label :birthday %>
<%= form.date_field :birthday, class: "employee__new__form__item-input" %>
</div>
<div class="employee__new__form__item">
<%= form.label :department_id, "Department:" %>
<%= form.collection_select :department_id, @departments, :id, :name, {prompt: "選択してください"}, {class: "employee__new__form__item-input"} %><br>
</div>
<%= form.submit class: "employee__button--blue" %>
<% if action_name == "new" %>
<%= link_to '社員一覧画面に戻る', employees_path, class: "employee__button--gray" %>
<% elsif action_name == "edit" %>
<%= link_to '社員の詳細情報を見る', employee_path(@employee), class: "employee__button--gray" %>
<% end %> <% end %>

Webブラウザを再読み込みすると、すでにemployees.scssで定義されているボタンのスタイルが適用されます。

employees.scssを開いて、SCSSでスタイルを定義しましょう。

以下のCSSをSCSSに書き換えて、employees.scssでスタイルを定義してみましょう。SCSSの書き換えは、CSSをSCSSに書き換えを参考にしてください。

CSS
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
.employee__new {
  margin-left: auto;
  margin-right: auto;
  width: 66%;
}

.employee__new-title {
  font-weight: 700;
  font-size: 36px;
  line-height: 40px;
  margin: 0;
}

.employee__new__form__item {
  margin: 20px 0;
}

.employee__new__form__item-label {
  display: block;
  font-weight: 700;
  margin-bottom: 4px;
}

.employee__new__form__item-input {
  display: block;
  margin-top: 8px;
  padding: 8px 12px;
  width: 100%;
  border-radius: 4px;
  border: 1px solid #E5E7EB;
  font-size: 16px;
  line-height: 24px;
  color: #575F74;
}

上記のCSSをSCSSに書き換えて、employees.scssで定義することができれば、新規作成画面は以下のような見た目になります。

employees.scssを編集したら、以下の「解答をみる」をクリックして、SCSSの書き方があっているかを確認しましょう。

解答をみる
答え
app/assets/stylesheets/employees.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
.employee {
  //中略
  &__index {
    width: 100%;
    //中略
  }

&__new {
margin-left: auto;
margin-right: auto;
width: 66%;
&-title {
font-weight: 700;
font-size: 36px;
line-height: 40px;
margin: 0;
}
&__form__item {
margin: 20px 0;
&-label {
display: block;
font-weight: 700;
margin-bottom: 4px;
}
&-input {
display: block;
margin-top: 8px;
padding: 8px 12px;
width: 100%;
border-radius: 4px;
border: 1px solid #E5E7EB;
font-size: 16px;
line-height: 24px;
color: #575F74;
}
}
}
&__show { // 中略

この記事のまとめ

  • application.html.erbは、アプリケーションで共通のレイアウト
  • <%= yield %>によって、個別のテンプレートが自動で埋め込まれて、最終な出力を生成する