2021年4月1日木曜日

リンク集の見栄えを整える(詳細編)【Rails備忘録】

あるWebアプリ開発においてリンク集の見栄えをよくした件,具体的にどんな作業をしたかをメモしておく.

本稿では,仮のアプリを作って,それを題材に説明する.仮のRailsアプリはrails newで新規のプロジェクトを作成した後にBootstrap4対応の作業を加え,次のコマンドを実行してホーム画面を作った状態とする.ここではその次のステップから説明を始める.

$ bin/rails g controller home index

なお,ルーティング設定は次のとおりconfig/routes.rbroot to: 'home#index' の一行を追加しておく.http://localhost:3000/にアクセスすると,ホームコントローラのindexメソッドが対応し,app/views/home/index.html.erbが表示されるという設定である.

Rails.application.routes.draw do

  root to: 'home#index'

  get 'home/index'

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html

end

この状態でhttp://localhost:3000/(ホーム画面)にアクセスすると,次のような画面が表示されるはずだ.


素のリスト

まずは素のリストを作成する.app/views/home/index.html.erbにリンクを列挙したコードを追記する(あと,少し見やすくなるように全体をcontainerで囲んだ).なんだかGoogleのサービスを並べてGoogleの回し者のようになってしまっているが,手頃なところということでこうなった.ご容赦いただきたい.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <ul>

    <li><%= link_to 'Calendar', 'https://calendar.google.com/' %></li>

    <li><%= link_to 'Mail', 'https://mail.google.com/' %></li>

    <li><%= link_to 'Map', 'https://maps.google.com/' %></li>

    <li><%= link_to 'Scholar', 'https://scholar.google.com/' %></li>

  </ul>

</div>

サーバを起動してホーム画面に再びアクセスすると,こんな画面になるはずだ.


それぞれをクリックすると,Googleのカレンダーやらメールやらのサービスに飛ぶはずである.

リストグループ化

ところで,これではいくらなんでも素っ気なさすぎる.なので,まずは,リストグループを使ってボタンの並びにしてみよう.

コードを次のように修正する.ulliをやめて,list-groupクラス属性を付けたdivタグで囲むようにする.個々のハイパーリンクは,list-group-itemのクラスとする.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <div class="list-group">

    <%= link_to 'Calendar', 'https://calendar.google.com/',

                class: 'list-group-item' %>

    <%= link_to 'Mail', 'https://mail.google.com/',

                class: 'list-group-item' %>

    <%= link_to 'Map', 'https://maps.google.com/',

                class: 'list-group-item' %>

    <%= link_to 'Scholar', 'https://scholar.google.com/',

                class: 'list-group-item' %>

  </div>

</div>

このようにすると,画面は次のようになる.マウスオーバーでハイパーリンク部分の色が少し濃くなり下線が付く.


少し修正しよう.各項目に,list-group-item-actionという属性を追加してみた.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <div class="list-group">

    <%= link_to 'Calendar''https://calendar.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to 'Mail''https://mail.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to 'Map''https://maps.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to 'Scholar''https://scholar.google.com/',

                class'list-group-item list-group-item-action' %>

  </div>

</div>

こうすると,見た目と動作が少し変化する.ハイパーリンクの青字がなくなってしまったが,ボタン状のセル全体がマウスオーバーでハイライト表示されるようになる.次図は,Mailのところにマウスポインタが当てられている状態である.


アイコンを追加する(準備)

多少,イマ風にはなったものの,まだ,なんとなくそっけない印象である.各項目にアイコンを追加してみよう.アイコンの素材はOcticonsを使う.

嬉しいことに,Railsに対応したgemが用意されている.まずは,Gemfileに次の行を追加しよう.

gem 'octicons_helper'

そして,インストールする.

$ bundle install

 ...

Using actionview 6.1.3.1

Fetching octicons 12.1.0

Using actionpack 6.1.3.1

 ...

Using sass-rails 6.0.0

Installing octicons 12.1.0

Fetching octicons_helper 12.1.0

Installing octicons_helper 12.1.0

Bundle complete! 18 Gemfile dependencies, 75 gems now installed.

Bundled gems are installed into `./vendor/bundle`

mac4:menu_example iiojun$

これだけで,octiconというメソッドが使えるようになり,SVGで描画されるアイコンが使い放題になる.SVGなので画像データのような外部リソースが不要というのも嬉しい.座標データのテキスト情報としてHTMLにそのまま埋め込まれるからである.

Railsコンソールでocticonメソッドの動作を確認してみよう.ハートのアイコン「heart」を表示させてみる.引数に与えるアイコン名の指定はシンボルでも文字列でもよい.svgタグで描画するHTML文字列が得られることが分かる.

$ bin/rails c

Running via Spring preloader in process 26925

Loading development environment (Rails 6.1.3.1)

irb(main):001:0> include OcticonsHelper

=> Object

irb(main):002:0> octicon :heart

=> "<svg class=\"octicon octicon-heart\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.565 20.565 0 008 13.393a20.561 20.561 0 003.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.75.75 0 01-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5zM8 14.25l-.345.666-.002-.001-.006-.003-.018-.01a7.643 7.643 0 01-.31-.17 22.075 22.075 0 01-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.08 22.08 0 01-3.744 2.584l-.018.01-.006.003h-.002L8 14.25zm0 0l.345.666a.752.752 0 01-.69 0L8 14.25z\"></path></svg>"

irb(main):003:0> 


アイコンを追加する(実践……失敗)

octiconメソッドを使うと,SVGのアイコンをコンテンツに埋め込むことができる.Octiconsのページにあるサンプルは次のようなものである(「alert」という名前のアイコンを埋め込んでいる).

<%= octicon "alert", :height => 32,  

 :class => "right left", :"aria-label" => "hi" %>

それを参考に,アイコンを追加してみよう.link_toで表示するコンテンツの中身なので,少し,工夫が必要である.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <div class="list-group">

    <%= link_to "#{octicon 'calendar', height: 24,

                     class: 'right left', 'aria-label': 'calendar'} 

                 Calendar",

                'https://calendar.google.com/',

                class: 'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mail', height: 24,

                     class: 'right left', 'aria-label': 'mail'}

                 Mail",

                'https://mail.google.com/',

                class: 'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'globe', height: 24,

                     class: 'right left', 'aria-label': 'globe'}

                 Map",

                'https://maps.google.com/',

                class: 'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mortar-board', height: 24,

                     class: 'right left', 'aria-label': 'mortar-board'}

                 Scholar",

                'https://scholar.google.com/',

                class: 'list-group-item list-group-item-action' %>

  </div>

</div>

さて,表示させてみる.どうなるだろうか?

おやおや?octiconメソッドが生成したSVGのソースコードがそのまま表示されてしまった.これはちょいと都合が悪い.

アイコンを追加する(実践……成功)

ここで,ちょっとした細工をする.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <div class="list-group">

    <%= link_to "#{octicon 'calendar'height24,

                     class'right left''aria-label''calendar'} 

                 Calendar".html_safe,

                'https://calendar.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mail'height24,

                     class'right left''aria-label''mail'}

                 Mail".html_safe,

                'https://mail.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'globe'height24,

                     class'right left''aria-label''globe'}

                 Map".html_safe,

                'https://maps.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mortar-board'height24,

                     class'right left''aria-label''mortar-board'}

                 Scholar".html_safe,

                'https://scholar.google.com/',

                class'list-group-item list-group-item-action' %>

  </div>

</div>

何をしたかといえば,表示するコンテンツの文字列部分に,html_safeというメソッド呼び出しを追加しただけである.

通常は,コンテンツに含まれるHTMLのタグなどは全てエスケープ処理が施される.したがって,コンテンツがHTMLのタグ文字列を含んでいたとしても,タグとしての機能は削除されタグ部分も文字列として表示される.そのために,先のようなSVGのソースコードが表示されてしまっていたわけだ.

html_safeメソッドは,「対象とする文字列はHTMLとして安全だから,そのまま表示していいよ」ということを指定するものである.同様の手段として,rawメソッドを使うという方法もある.

さて,再度,挑戦する.どうなるだろうか?


今度はうまくいった.ついでに,アイコンとラベルの間に隙間を空けて,末尾に「»」マークを付けておこう.&nbsp;(non-break space)と&raquo;(right angle quote)を使う.Calendar,Mailなどラベル文字列の前後にそれぞれを追記した.ソースコードもいささか複雑になってきた.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <div class="list-group">

    <%= link_to "#{octicon 'calendar'height24,

                     class'right left''aria-label''calendar'} 

                 &nbsp; Calendar &raquo;".html_safe,

                'https://calendar.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mail'height24,

                     class'right left''aria-label''mail'}

                 &nbsp; Mail &raquo;".html_safe,

                'https://mail.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'globe'height24,

                     class'right left''aria-label''globe'}

                 &nbsp; Map &raquo;".html_safe,

                'https://maps.google.com/',

                class'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mortar-board'height24,

                     class'right left''aria-label''mortar-board'}

                 &nbsp; Scholar &raquo;".html_safe,

                'https://scholar.google.com/',

                class'list-group-item list-group-item-action' %>

  </div>

</div>

表示はこんな感じになる.だいぶいい感じになった.


仕上げ

かなりいい感じになったが,「ハイパーリンクですよ」ということを表すために,ラベル部分は青色にしておいたほうがよさそうだ.Bootstrap4のtext-primaryを使えばよい.

文章中の一部分だけ,部分的に見た目を変えるには,spanタグでその部分を囲んであげればOKである.具体的には,<span class="text-primary">Calendar</span>というように,text-primaryのクラス属性を持つspanタグで囲む.それにはcontent_tagメソッドが利用できる.それぞれのラベル部分を,content_tagメソッドの処理結果を差し込むように修正した.

……というわけで最終的なコードはこうなった.だいぶ長くなったが,順を追って育ててきたので,読み解くのはそれほど難しくないだろう.

<div class="container">

  <h1>Home#index</h1>

  <p>Find me in app/views/home/index.html.erb</p>

  <h2>The Link List</h2>

  <div class="list-group">

    <%= link_to "#{octicon 'calendar', height: 24,

                     class: 'right left', 'aria-label': 'calendar'} 

                 &nbsp; 

                 #{content_tag :span, 'Calendar',

                     class: 'text-primary'} 

                 &raquo;".html_safe,

                'https://calendar.google.com/',

                class: 'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mail', height: 24,

                     class: 'right left', 'aria-label': 'mail'}

                 &nbsp; 

                 #{content_tag :span, 'Mail', class: 'text-primary'} 

                 &raquo;".html_safe,

                'https://mail.google.com/',

                class: 'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'globe', height: 24,

                     class: 'right left', 'aria-label': 'globe'}

                 &nbsp; 

                 #{content_tag :span, 'Map', class: 'text-primary'} 

                 &raquo;".html_safe,

                'https://maps.google.com/',

                class: 'list-group-item list-group-item-action' %>

    <%= link_to "#{octicon 'mortar-board', height: 24,

                     class: 'right left', 'aria-label': 'mortar-board'}

                 &nbsp; 

                 #{content_tag :span, 'Scholar', class: 'text-primary'} 

                 &raquo;".html_safe,

                'https://scholar.google.com/',

                class: 'list-group-item list-group-item-action' %>

  </div>

</div>

表示結果はこのようになる.出発点と比べると,だいぶ洗練されたデザインになったのではなかろうか.



0 件のコメント:

コメントを投稿