ME to FE

デザインからフロントエンドのことまでごちゃまぜで綴ります

CSSフレームワークからみる、フォーカス・インジケータの違いを考察

f:id:saimari02:20191222172727p:plain
CSSフレームワークからみる、フォーカス・インジケータの違いを考察

フォーカスってなに?

「フォーカス」とは、パソコン画面上でウインドウや入力ボックス、アイコンやボタン、画像といった対象物が「次の操作」を受けられる(アクティブな、選択された)状態のことです。
引用:weblio辞書「フォーカス」(別窓でリンク)

入力フォームのフォーカスが確認できる動作サンプル動画 上記の動作サンプルを例にすると、テキストフォーム、セレクトフォーム、ラジオボタンチェックボックス、送信ボタンなど、選択時に色付きの枠(※Google Chrome上での場合)など、「選択中」ということが可視化できるよう装飾されます。
この装飾を「フォーカス・インジケータ」といいます。

フォーカスの可視化について

ユーザーの中には、運動障害のある人、盲目の人、手を持たない人、何らかの理由でマウスやトラックパッドを使用できない人もいます。

このようなユーザーは、キーボードのTabキーや、操作補助ツールなどでフォーカス・インジケータを頼りにWebサイトを閲覧、操作することがあります。

WCAG2.1では、Webサイトをキーボードで操作できるようにすること、キーボード フォーカスを持っている要素をユーザーが認識しやすくすること、などの達成基準の項目が存在します。
フォーカス・インジケータについては、[達成基準 2.4.7 フォーカスの可視化] で上げられています。

キーボード操作が可能なあらゆるユーザインタフェースには、フォーカスインジケータが見える操作モードがある。
(レベル AA)
引用: Web Content Accessibility Guidelines (WCAG) 2.1の達成基準 2.4.7 フォーカスの可視化(別窓でリンク)

フォーカスのスタイル

ここで問題なのは、ブラウザごとにフォーカス・インジケータのスタイルが異なることです。

この場合、ブラウザ間の差異を無くすために、CSS:focus の擬似クラスでスタイルを変更することが可能です。

よく上げられる問題として、このフォーカス・インジケータがWebサイトのトンマナに合わない、視覚的に美しくない、などの理由で消されてしまうケースです。

:focus {
    outline: none; // DON’T DO IT!
}

この指定をしてしまうと、キーボードユーザーが要素にアクセスできなくなるために、絶対にやめましょう。

CSSフレームワークはどのような対応をしているのか?

業務でBULMAや、Bootstrapを使用することがあり、フォーカス・インジケータのスタイルが細かく設定されていてとても助かったことがあります。

フォーカススタイルをどう当てているのか気になったので、以下5つのフレームワークを比較してみたいと思います。

※各フレームワークの特徴はここでは省きます。 ※formで使われる代表的な要素(inputbuttonなど)で比較します。

BULMA

BULMAの例をCode Penのレイアウトビューで見る(別窓でリンク)

特徴

// 一部抜粋
.input:focus {
    border-color: #3273dc;
    box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
    outline: none;
}
  • input[type="text"], selectbox, button:focus のスタイルはoutline: none;をしてbox-shadowプロパティで別でスタイル付与。
    • フォーカスリングは色がやや薄め。
  • input[type=checkbox], input[type=radio]は、ブラウザデフォルトのスタイル。

Bootstrap

Bootstrapの例をCode Penのレイアウトビューで見る(別窓でリンク)

特徴

// 一部抜粋
.form-control:focus {
    color: #495057;
    background-color: #fff;
    border-color: #80bdff;
    outline: 0;
    box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}
  • input[type="text"], selectbox, button, input[type=checkbox], input[type=radio]:focus のスタイルはoutline: none;をしてbox-shadowborder-colorプロパティで別でスタイル付与。
    • 上記の要素はフォーカス・インジケータを全て独自スタイルで担保している。
    • フォーカスリングはやや太め。

Materialize

Materializeの例をCode Penのレイアウトビューで見る(別窓でリンク)

特徴

// 一部抜粋
input:not([type]) {
  outline: none;
}

input[type=タイプ別の記述]:not(.browser-default):focus:not([readonly]){
    border-bottom: 1px solid #26a69a;
    -webkit-box-shadow: 0 1px 0 0 #26a69a;
    box-shadow: 0 1px 0 0 #26a69a;
}
select:focus {
    outline: 1px solid #c9f3ef;
}
  • input[type="text"], は独自スタイルでborder-bottomが変わるのみ。
  • selectboxは独自スタイルでborder-bottomの色が変わるパターン(JavaScriptが使われている)と、ブラウザデフォルトスタイルでoutlineで色が変わる2パターン用意されている。
  • button類のスタイルは全てbackground-colorが変わるのみ。outline: 0;されている。
  • input[type=checkbox], input[type=radio] は独自スタイルで、:checkedの擬似クラスでフォーカス・インジケータが担保されている。

Pure.css

Pure.cssの例をCode Penのレイアウトビューで見る(別窓でリンク)

特徴

// 一部抜粋
.pure-form input[type=タイプ別の記述]:focus {
    outline: 0;
    border-color: #129fea;
}

.pure-form input:focus:invalid {
    color: #b94a48;
    border-color: #e9322d;
}
  • input[type="text"], selectbox:focus のスタイルはoutline: none;をしてborder-colorプロパティを別でスタイル付与。required 属性がある時は強制的に赤色。
  • button類のスタイルは全てbackground-colorが変わるだけ。outline: 0;されている。
  • input[type=checkbox], input[type=radio]outlineプロパティで独自の色を指定している。

skeleton

Skeletonの例をCode Penのレイアウトビューで見る(別窓でリンク)

特徴

// 一部抜粋
input[type=タイプ別の記述]:focus {
    border: 1px solid #33C3F0;
    outline: 0;
}

.button:focus {
    background-color: #1EAEDB;
    border-color: #1EAEDB;
    outline: 0;
}
  • input[type="text"], selectbox:focus のスタイルはoutline: none;をしてborder-colorプロパティで別でスタイルを付与。
  • button類のスタイルは全てbackground-colorborder-colorが変わるだけ。outline: 0;されている。
  • input[type=checkbox], input[type=radio] はブラウザデフォルトのスタイル。

CSSフレームワークの総評

検証の結果、WCAG2.1 [達成基準 2.4.7 フォーカスの可視化] の配慮ができているであろうフレームワークの順位は以下のようになりました。

※あくまで個人の主観のもと、順位づけさせていただきました。

  1. Bootstrap
  2. BULMA
  3. Pure.css
  4. Skeleton
  5. Materialize

1. Bootstrap

フォーカス・インジケーターがつく要素はほぼ独自スタイルで賄えており、且つ太めで見やすい。
ブラウザデフォルトの青枠に寄せているので、ユーザーも困惑しにくいと思われる。

2. BULMA

フォーカス・インジケーターのスタイルは控えめだが、視覚的な美しさは担保できている。
フォーカスリングの付け方はBootstrapと大差ないが、独自スタイルとブラウザデフォルトの混在が気になる。

3. Pure.css

buttonのフォーカスリングを消してしまっているのが残念。
inputrequired属性がある時に勝手に赤色にしてしまうのは、ちょっとお節介かも?色だけで判断させるのは良くないので、補足のラベルを付ければベストかもしれない。

4. Skeleton

最低限のスタイル付与と軽さが売りのフレームワークなので、:focusスタイルも最低限。
Pure.css同様buttonのフォーカスリングを消してしまっているのが残念。

5. Materialize

独自スタイルが多く、UX重視な印象。
フォーカス・インジケータのスタイルに統一感がないのと、目立ちにくいため、認識のしやすさに欠ける。
Pure.css同様buttonのフォーカスリングを消してしまっているのが残念。

まとめ

Bootstrapはコンポーネントごとに細かい配慮が施されており、至れり尽くせりな感じでした。

クラッチで書く場合は、:focusスタイルはbox-shadowプロパティでスタイル付与するのが良さそうです。 色はブラウザデフォルトの色に合わせるのがUX的にも無難ですが、Webサイトやサービス全体のトンマナに合わせるのでも良さそう。

フォーカスがどこにあるのかを見つけることができるようになることが目的なのでスタイルは付与は自由だけれども、塩梅は大事にしたいと思います。

Webアクセシビリティの中でも、フォーカスの可視化を100%担保することは難しく実装ではよく苦戦するため、今回のテーマを取り上げてみました。 是非、皆さんが日頃フォーカスのために行なっていること教えていただけると嬉しいです!

(Pug)繰り返すのはイヤだ!!! listで使えるmixinコード

f:id:saimari02:20190515214913p:plain
繰り返すのはイヤだ!!! listで使えるmixinコード(Pug)

Pugを使いこなしたい!

「もっとPugを使いこなしたい!」
と思っている方いませんか??

私は業務ではPugを使ってマークアップをしています。
最初のうちは変数を使ったりするだけで、ほとんどPugを使いこなせていませんでした。
そんな私でも導入できたmixinのコードを紹介します。

内容

リスト形式のニュース一覧を例に、 <ul><ol>のリストで役に立ちそうな書き方をmixinを使って実装してみます。

記述例(Pug)

ul.news__list
    mixin news-list(...newsLists)
        each news, index in newsLists
            li.news__item
                a.news__link-post(href=news.linkHref,target=news.linkTarget,rel=news.linkTarget === '_blank' ? 'noopener noreferrer' : '')
                    .news__number #{index + 1}
                    .news__category= news.category
                    .news__date= news.date
                    .news__title= news.title
                        if news.iconNew == true
                            span.icon--new NEW
    +news-list(
        {
            linkHref: '/news-20190521/',
            linkTarget: '_blank',
            category: 'カテゴリー名',
            date: '2019.05.21',
            title: 'タイトル2',
            iconNew: true,
        }, {
            linkHref: '/news-20190520/',
            category: 'カテゴリー名',
            date: '2019.05.20',
            title: 'タイトル1',
            iconNew: false,
        }
    )

コンパイル後(html)

<ul class="news__list">
    <li class="news__item">
        <a class="news__link-post" href="/news-20190521/" target="_blank" rel="noopener noreferrer">
            <div class="news__number">1</div>
            <div class="news__category">カテゴリー名</div>
            <div class="news__date">2019.05.21</div>
            <div class="news__title">タイトル2<span class="icon--new">NEW</span></div>
        </a>
    </li>
    <li class="news__item">
        <a class="news__link-post" href="/news-20190520/" rel="">
            <div class="news__number">2</div>
            <div class="news__category">カテゴリー名</div>
            <div class="news__date">2019.05.20</div>
            <div class="news__title">タイトル1</div>
        </a>
    </li>
</ul>

パーツごとに解説

1. 定義

mixin news-list(...newsLists)

まずnews-listという名前で、mixinを定義します。(この例ではli全体を対象としています)
Rest引数を利用し、...newsListsの配列全てを受け取ります。

参考: 分割代入や引数の「残り全部」を持ってくるやつ……。(現代的JavaScriptおれおれアドベントカレンダー2017 – 17日目) | Ginpen.com

2. 繰り返しの指定

each news, index in newsLists

each in文を使います。
newsnewsListsの値を、
indexnewsListsのインデックス番号が格納されています。

3. 要素の中に引数を指定

li.news__item
    a.news__link-post(href=news.linkHref,target=news.linkTarget,rel=news.linkTarget === '_blank' ? 'noopener noreferrer' : '')
        .news__number #{index + 1}
        .news__category= news.category
        .news__date= news.date
        .news__title= news.title
            if news.iconNew == true
                span.icon--new NEW

この例では、引数のnewsListsをオブジェクトで返すため、変数名.プロパティ名でそれぞれ記述していきます。
以下の通りです。

  • news.linkHref
  • news.linkTarget
  • news.category
  • news.date
  • news.title

※オブジェクトの内容は追って説明します。


a.news__link-post(href=news.linkHref,target=news.linkTarget,rel=news.linkTarget === '_blank' ? 'noopener noreferrer' : '')

rel属性の値を、三項演算子で出し分けしています。
traget属性に_blank(別窓ウィンドウでリンクを開く)の値が入っているときは、rel属性にnoopener noreferrerを代入します。

rel="noopener noreferrer"については、以下を参考にして下さい。ここでは省略します。

参考: リンクを作る時の target="_blank" の危険性 - 隙あらば寝る


.news__number #{index + 1}

#{index + 1}で配列のインデックス番号を取得していますが、プログラミング言語のインデックス番号は0から始まるため、+1をして強制的に1から始まるようにしました。

ここで悩ましいのは#{index++}とインクリメント演算子で記述すればよくない?
と思いましたが、、結果、どうやらできないらしい・・・!!
あくまで配列のインデックス番号を取得するのみということなのか・・・。
うまく説明できないので、お分かりの方お力添えをお願いします!


.news__title= news.title
    if news.iconNew == true
        span.icon--new NEW

if文を使って、NEWの表示を出すか出さないかの判定をしています。
trueであればspan.icon--new NEWが出力されます。

※ここではtrue以外の値を指定すれば出力されませんが、有無がわかるようにtruefalseのどちらかを指定します。

4. 出力結果の指定

+news-list(
    {
        linkHref: '/news-20190521/',
        linkTarget: '_blank',
        category: 'カテゴリー名',
        date: '2019.05.21',
        title: 'タイトル2',
        iconNew: true,
    }, {
    ~~ 省略 ~~
    },
)

mixinで定義したnews-listを呼び出します。
呼び出し方法は、+とmixin名を指定します。
オブジェクトのプロパティ名と内容は、以下の通りです。

プロパティ名 内容
linkHref リンクパスの記述
linkTarget 別窓リンクの場合_blankを記述
category カテゴリー名の記述
date 日付の記述
title タイトルの記述
iconNew NEWの表記が必要な場合trueを、不必要であればfalseを記述

補足

この例では、mixinの定義と呼び出しを1ファイル内で行いましたが、mixinの要素だけ別ファイル化し、includeして使うことも可能です。

  • mixinの数が増えてきたら、mixinだけをまとめた別ファイルで管理する。
  • コンポーネントとしてmixinを使用する場合は、コンポーネントごとに別ファイルで管理する。

まとめ

同じ記述を何度も繰り返すのイヤですよね??
それに、同じ記述を手作業で増やすことで、思わぬミスが発生することもあります。
変更箇所を必要最低限に抑えることで、作業の手間とミスを減らすことが可能です!
なんてHAPPYなんだ〜!

今回紹介した記述例の中には、mixin以外にもPugのちょっとした小技を盛り込んだので是非他のところでも応用してみて下さい。

Pug公式ドキュメント

デザイナー経験の価値について思ったこと

f:id:saimari02:20190421045821p:plain
デザイナー経験の価値について思ったこと

初LT登壇!

先日参加したイベントで、初LTで発表させてもらいました。

【Hedge #2】「デザイナー × エンジニア = ∞」を実現するために僕らがやれること - connpass

私はデザイナーからマークアップエンジニアになったのですが、そんな立場の人間から何か伝えられたらなと前々から思っていたので、エイヤー!といつの間にかLT枠で申し込んでいました。
以下がLT発表時のスライドです

スライドの一部内容は当日公開したものから変更しています。

1. デザインから実装までノンストップ

優先度を意識して伝えるべきことを形にするためにデザインし、文書構造を意識してマークアップをする。
両者の共通点は情報設計で、根本でやっていることは同じだと思っています。
だとすれば、デザイン時にはすでに頭の中でアウトライン化が始まっていて、脳内マークアップが同時並行で開催中ということになります。
デザインと実装どちらも担当した時は、私はそんな感じでした。

その代わり、型破りで革新的なデザインは意識しないと生まれなくなってしまうんです。なぜならマークアップは型通りにしないといけないですからね…。
時には型から外れないといけない時もある!

2. デザイナーと意見しあえる

以前エンジニアさんと話をしていて、「デザインは全くわからないから。。」「デザイナー怖いじゃん。。」という発言を耳にして、驚いた経験があります。

お陰様で私はそんな風に思ったことがないし、むしろ上がってきたデザインについて、あーだこーだ聞きまくる・確認しまくる・時に意見しちゃうタイプです。
特に分業だとここはすごい大事なポイントのはずです。
デザイナーとエンジニアのコミュニケーション不足のために後々あれが違う、この場合はどうなる、なんて揉めること皆さん日常茶飯事でしょう?(そんな記事を見た覚えがある)
私はそういう厄介ものは真っ先に潰しにいきます!

その点ではデザインの知見があるからこそできるコミュニケーションもあるんですよね。
経験がこういうところで役に立つものなんですね。

3. デザイナーめっちゃ尊い

デザインって正解がないじゃないですか?
特に受託で制作をやっていると、求められるデザインって案件によって全く違うし、その数こなすのって本当に大変なんですよ。
0から1をひたすら生み続ける素晴らしさ、尊敬しかないです!

あと、私たちエンジニアはその見た目をコンピューターに伝えるためにコード化したり、パフォーマンスを良くしたりしていますが、極論それって裏方…。
ユーザーにダイレクトに何か物事を伝えられる役目はデザイナーだと思っています。

「見た目が9割」と、スライドの内容で誤解を生みそうなことを書いてしまったので、Twitterで補足しました。

もちろんエンジニアだって技術で救えることがあるってこと、忘れちゃないですよ!

LTまとめ

LTで話した3つのことについて書いてきました。
デザイナーもエンジニアもお互いが少しでも知ろうとすることで、円滑に物事が進んだり、結果的に出来上がるもののクオリティーがぐっと上がると思っています。

皆さん、お互いの壁をぶち壊す勢いで仲良くやっていきましょう!

あと、何事も無駄な経験はないよねってことが大まかな感想です。

デザイナー経験の価値って?

ここからはLTの発表とは話が逸れるのですが、私が現在転職活動中でしてその中のお話です。

エンジニアとして応募をして話を聞きに行ったりすると、ありがたいことにどこの企業もデザイナーの経験について食いついてくれます。

「なんでデザイナーからエンジニアになったの??」
「デザインの経験は十分にあるから、その経験も是非活かして欲しい」

私はむしろ、デザインナーとしてもエンジニアとしても、経歴が中途半端なんじゃないか、とネガティブに捉えていました。
もちろんそう感じられた企業もあるかと思いますし、それが要因で選考落ちた経験もしました。

それよりも、エンジニアにもデザイン力を必要とするケースが増えている(企業による)、という事実を知ったのは大きな収穫です。
デザイナーが経営に関わるべきだ、と言われている昨今、デザイナーの需要が高まっているのは確かなのかもしれませんね。
デザイナー経験の価値はこれから上がってくると思っています。

迷っていたけど腑に落ちたこと

私は欲張り者です。
3年前エンジニアに転身しようと思った時、デザイナーの経験を捨てられずに、まぁどっちもやっていけばいっか!てへぺろ。ぐらいな生半可な気持ちでいました。
3年間そのつもりでやってみてわかったことは、どちらも名乗るには相当な努力が必要だということです。

  • どちらかに集中しすぎて、片方の手を少しでも止めたらその分どちらかの手が鈍る
  • 求められることの領域がフロントエンド全般で、ひ、広すぎ...(泣
  • からの〜フロントエンド界隈の知識の幅広さについていくのが大変...(泣

デザイナーとしても、エンジニアとしても完璧にやっていこうとすると、睡眠時間0になりそうな勢いでした。
それは無理だなと気づき、それでもどちらか一方を捨てることができない私はやっぱり欲張り者です。(2回目)

仕方ないので、どちらもゆっくりやっていけば良いかと。
1年で100はできないけど、1年で10やって10年後に100になればいいかなと思うようになりました。
続けていれば、そのうちできていることもあるんです!ははは(そんな甘くないというご意見もびしばしどうぞ)

胸を張って「デザイナーもエンジニアもやっています」と言えるように、これからもエンジニアの傍で細々とデザインは続けていくつもりです。