Hatena::ブログ(Diary)

Webデザインの日々日記 RSSフィード

2017-02-18

全ブラウザ/レスポンシブデザイン対応、HTMLの入れ子を増やさずにCSSで背景画像を半透明にする方法

用途

  • divとかのボックスに半透明の背景画像を付けたい。
  • ただし中の要素まで半透明にされると困る。
  • レスポンシブ対応で、ボックスの縦横比が変わっても背景画像はボックス全体をカバーするように。

課題

背景画像を設定し、普通にopacityをかけると中の要素まで半透明になって困る。

解決法

考え方

背景画像を設定したボックスにopacityを付けると、子要素まで半透明になるのなら、子要素の入らないbefore疑似要素に背景画像を設定すればいい。

before疑似要素をposition: absolute;を使ってボックス全体をカバーすれば目的は達成できる。

なお、after疑似要素でも同じことができるけど、ここはclearfixが使えるように開けておきたい。

コード構成

HTML

<div class="background-opacity">
  コンテンツ類
</div>

CSS

.background-opacity {
  position: relative;
  z-index: 0;
}
.background-opacity::before {
  content: " ";
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background-image: url(背景画像のパス);
  background-size: cover;
  background-position: center center;
  opacity: 0.35;
}
.background-opacity * {
  position: relative;
}

コード解説

.background-opacity::before

まず、contentプロパティにスペースを入れることでbefore疑似要素を有効にします。。

  content: " ";

次に、before疑似要素を親要素である.background-opacityの領域全体に広げます。

  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;

display: block;でwidth, heightプロパティを使えるようにしています。

これはブロックレベル要素であればよいので、display: inline-block;やdisplay: table;でも同じような動作をしてくれるはずです。

そしてposition: absolute;を使って、.background-opacityの子要素がbefore疑似要素に重複するようにします。

また、top と left プロパティは、デフォルトではbefore疑似要素が.background-opacityのpaddingなどの影響を受けてしまうので、0の値を入れます。

最後にメインディッシュの背景画像の半透明化です。

  background-image: url(背景画像のパス);
  background-size: cover;
  background-position: center center;
  opacity: 0.35;

背景画像は、画像のボケを許容する場合はボックスより小さいサイズでもOKです。ボケを発生させたくない場合は、画像の高さ、幅とも、想定される最大値を超えるようにしなければなりません。つまり、パソコンの画面で想定される最大幅以上の幅、スマホの縦長のサイズにしたときの最大の高さ以上の高さとなる画像を用意します。

background-sizeは、基本的にcoverを使って、ボックスからあふれる分はトリミングされるようにしています。デザインによっては他の値を入れてもよいでしょう。

background-positionは、今回の例では画像の中央が常に表示され、端の方はトリミングされてもOK,という形になっています。写真によって配置場所は変えるとよいでしょう。

最後に、opacityで写真の透明度を設定し、before疑似要素の調整は終了です。

.background-opacity

これはbefore疑似要素の親要素になるため、position:relative;を設定する必要があります。

  position: relative;
  z-index: 0;

z-index: 0;の設定が地味に重要で、デフォルトだとbefore疑似要素が他の子要素の上を覆ってしまいます。

.background-opacity *
  position: relative;

最後に、.background-opacity の子要素全てにposition: relative;を設定します。

この設定にはz-index: 1;が隠れています。(デフォルトの設定)

これで全ての子要素がbefore疑似要素より上に配置されます。

カラーフィルター効果への応用

試してはいませんが、背景画像を.background-opacityに設置、before疑似要素にbackground-colorをrgbaでセットすると、背景画像へのカラーフィルター効果が得られるはずです。もしかしたらz-indexの値を.background-opacityは0、before疑似要素は1、.background-opacity * には2を設定する必要があるかもしれません。

この方法の利点と欠点について

利点

HTMLの入れ子が増えないので、HTML側のメンテナンス性が上がります。

rgbaを使わず、シンプルにopacityで透明度をコントロールできます。

なんとなくハック感があって書いてて楽しい。

欠点

子要素のz-indexを制御するための設定で詳細度を上げている(しかもユニバーサルセレクタを使っている)ため、子要素内でpositionプロパティを使ったレイアウトを使う場合にはほぼ確実に干渉する。その場合は素直にHTMLを入れ子にして半透明フィルタをかける方がよいでしょう。

またCSSのコード量が、HTMLを入れ子にする方式より増えます。

疑似要素やpositionプロパティを使い慣れない初級のコーダーにとっては難解なコードとなる恐れもあります。誰でもメンテナンスできるように、という観点からはあまり好ましくない方法かもしれません。

まとめ

現状のCSSの仕様で簡単にコーディングできないデザインを実現するのは、コーダーの腕の見せ所でありやってて楽しいポイントでもあります。

しかし簡単に実現できないデザインである以上、HTMLかCSSか、あるいはその両者にしわ寄せが行き、コード量の増大、可読性、メンテナンス性の低下を招きます。その負担をHTML側にするのか、CSS側にするのかはコーダーの価値観やサイトの使われ方によって判断が分かれます。

今回の方法はCSS側が負担する手法として使ってもらえればと思います。

2017-02-10

カスタムフィールドに入力した電話番号を表示と発信リンクに使う

やりたいこと

  • カスタムフィールドで電話番号を入力してもらうのだが、ハイフンなしとかありとか、入力する人が面倒にならないようにしたい。
  • その電話番号はそのページで出力するのだが、スマホなど、タップしたら発信するように<a href="tel:〜〜">も付けたい。発信する方はハイフンなしにしなきゃいけない。

解決方法

以下、カスタムフィールドのkeyとして"tel"を使っている前提です。

<?php $tel_num = get_post_meta( get_the_ID(), 'tel', 'true' );
$tel_link = str_replace(array('-', 'ー', '−', '―', '‐','(',')','(',')',' ',' '),'',$tel_num);?>
<p>電話番号:<a href="tel:<?php echo esc_html($tel_link);?>"><?php echo esc_html($tel_num);?></a></p>

ハイフンの全角パターン、あと市内局番を括弧で囲まれてしまった場合、スペースが紛れ込んだ場合に備えてそれらをすべて削除するコードにしています。

参考にした記事

フォームで電話番号のハイフンを削除する時の注意点 | テクブロ

ハイフンを削除して電話番号リンクを設定する | 忘却の彼方 | 560Days

2017-02-06

WordPress4.7.2への更新完了メールが届いていたにもかかわらず、実際は更新されていなかったので管理者はちゃんと管理画面で確認を。

今回のWordPress4.7.2のアップデートがかなり緊急かつ重要であることが明らかになっています。

現在私が管理しているサイトについて、「WordPress 4.7.2 へ自動更新しました。」と、いつものメールが届いていたので安心していたのですが、管理画面を見ると「更新してください」のメッセージがあり、自動アップデートされていないことが分かりました。もちろん大急ぎですべてのサイトの管理画面をチェック。すべてのサイトで未更新であることが分かったので手動アップデートを緊急に行った次第。

サーバーはXserverを使っていますが、サーバー側の問題かどうかは分かりません。


一体何が起きていたのかさっぱりわからないのですが、サイト管理者はメールによるお知らせに安心せず、個別に管理画面で確認した方がよいでしょう。

2017-02-04

アクセシビリティと頭文字語の処理

a11y界隈では珍しくトゲのある議論を見かけたのでちょっと追いかけたら面白い課題に出くわしたという話です。

最初に見たのがこちら

とくに電子書籍の誤読問題に関するdisトーク

電子書籍の読み上げで「IT」が「イット」と読み上げられてしまうのを避けるために「I T」のように空白を入れるというバッドノウハウを自慢気に語る人たちがいて嘆かわしいという話。そんな非生産的で副作用の大きいクソみたいな単純作業をするくらいなら、読み上げソフトに機械学習を導入して根本的に誤読を減らす方がエンジニアリング的に正しい道だと思います。

http://sho.tdiary.net/20170201.html

まあEPUBを「E PUB」と書いている時点で読者を馬鹿しているのかな、という感想です。

http://momdo.hatenablog.jp/entry/20170202/1486036120

ハンドアックスがぶん投げられてるのを見るのは久しぶりだなーとか変な感想を持ちつつ、a11y周りではこういう"けちょん♪"という感じの議論は珍しいなと思った次第。

こういう流れだったっぽい

議論をたどっていった結果、以下のようなことがあった模様。

  1. 1月30日に東洋大学で「『電子書籍アクセシビリティの研究』公刊記念シンポジウム」が開催された。
  2. 当該書籍では音声読み上げで誤読を0にした
  3. 誤読0にするための著者側でのテクニックが紹介されていた
  4. そのテクニックの一部はよくないとWeb系のa11y関係者は感じた
  5. また読み手の視覚障害者からも「誤読はこっちで脳内修正するからあまり気にすんな」との声も出ていた。
  6. その後の飲み会でヒャッハーした
  7. これはバッドノウハウだろうとの記事がいくつか上がった

ってな状況のようで。

昔のはてな界隈でよく見たサツバツ感が足りませんが、けちょん、って空気が出てきたのはこの界隈にとってはあまりよくない気がします。「善意が空回り」ってのをdisってもねぇ、と。やっちまった著者陣は赤っ恥でしょうが後に続くおいらたちにとっては貴重な事例なわけでありまして。おかげでa11yの知識も増えましたし。

論点整理

  1. 音声読み上げソフトの「誤読」はかなりの頻度で発生する。
  2. 現状では読み手の視覚障害者たちが誤読として理解し処理している。
  3. 著者側で取りうる誤読対策として、頭字語の文字間にスペースを入れる、書き方を変える、読みを補足するの3点があげられる。
  4. このうち読み補足以外の手法には異論がある。

前提知識として、

頭字語とは

イニシャリズム (initialism):頭文字を一字ずつアルファベットの名のままで読むもの。例: FBI(エフ・ビー・アイ)、OECD(オー・イー・シー・ディー)、WHO(ダブリュー・エイチ・オー)など。

アクロニム (acronym):連なったアルファベットを通常の単語と同じように発音して読むもの。例: AIDS(エイズ)、OPEC(オペック)、NATO(ナトー)など。

https://ja.wikipedia.org/wiki/%E9%A0%AD%E5%AD%97%E8%AA%9E

ウェブアクセシビリティ上の扱い(WCAG2.0)ではイニシャリズム(頭文字語と訳している)への空白文字の挿入は不適合とは断じていない。

「空白文字」については、

F32の解説でいうところの空白文字、原文では"white space characters, such as space, tab, line break, or carriage return"というのがどのような集合を指すのかがあやふやなのが気になるところ。

http://momdo.hatenablog.jp/entry/20170202/1486036120

これたぶん、文字をdivとかで囲んでdisplay:inline-block;で並べた時に正体不明の余白を生じさせるあれ(普通じゃ見えない文字)じゃないですかね。

考察

基本的に音声読み上げソフトはまだ発展途上にあって、誤読問題を抱えていると。

それを現状で何とかしようとした結果が今回の問題であって、これとどう向き合っていき、どうしていけばいいかを俺たちゃ考えなきゃいけないわけです。

現状のまま読み手側が勝手に修正解釈するのに甘えるってのは書き手・編集・エンジニアのコケンに関わるので無しって方向で。

今回著者側からの提案

  • 用字変更・その他(例:IT → I T)
  • 表現変更(例:3/4 → 4分の3)
  • 読み補足(例:AA → AA(ダブルエー))
http://kidachi.kazuhi.to/blog/archives/039318.html

があって、少なくとも1つ目のスペース入れるのは読み上げソフト特化型のハックであり、マシンリーダブルとは言えない(検索性が著しく劣化する、また機械翻訳がまともに機能しなくなる恐れも)、晴眼者向けにも違和感を生じさせるため、むしろアクセシブルとは言い難いのではないかと思います。

表現変更については、書き手の表現の幅を狭めるので編集側のコケンにかかわるだろうと。

本手法に対しては、「ワープロのルビ機能も使えず、プレーンテキストしか書けない人が全部引き受けようとして無理をしている対策」という印象を受けます。

ここはエンジニア・コーダー側の出番ではないかと。

案1 rubyタグで処理

HTMLコーダーの目からすると、「これら全部ruby要素とかで処理できないか?」って思うんですがどうなんでしょう。

まだ試してないんですが、cssのメディアクエリのspeechとか使ってごにょごにょしたら通常の読み上げでは振り仮名を、単字送りでは漢字の方を読み上げさせることできないかなー、というのを以前から考えていて、それで読みの補足と表現変更分はカバーできるんじゃないかというのが私の考え。

で、頭字語についても、rubyかabbrタグでどうにかできないかなと。

この案の欠点は、単にスペース入れるだけよりはるかに膨大な手間がかかるってところでしょうか。

電子書籍化する段階で置換すれば手間が省けますが、今度は誤置換を防ぐノウハウが必要になります。原稿の段階では単語の前後にアンダースコアを入れるとか、置換時に単純検索ではなく正規表現を駆使して誤置換を防ぐとかいう形になるのではないかと思います。

案2 規格を変えてしまえ

最初は<initialism>タグができるといいんじゃね?、とか書くつもりだったのだけれど、ググってみたらなんかあったわw。

提案中なのか却下されたのかよく分かりません。

案3 書籍ごとに辞書付けたら?

HTMLのメタタグみたいなもので、単語と読み方の指示を先に書いておく。

リーダー側でそれを読み込んで、正しく読み上げる、という仕組み。リーダー側の対応が必要である課題は残るものの、書き手側の負担は最小限に抑えられ、表現の幅も確保できるはず。ヘッダーとかに分離しておけるのでこの技術が不要になっても悪い影響は残らない。

将来は機械学習に置き換わるにしても、その学習データとして有効に活用できるのではないかと思います。

案4 JavaScriptでどうにかできないか

案1、4を現状で実現するのに、JavaScriptを使って検索・置換して対応する。

一体どういうコードになるのかなんてのは分からんわけですが、著者・編集側の負荷をほとんど増やさずにできるのではないかなと。

とりあえず

EPUBのリーダーとか持ってないので検証できないんですが、パソコンの読み上げで誤読させないようにできるか、そのうち試してみようと思います。

本当は試してから記事上げたかったのですが、あまり余裕ないんで先にアイデアだけ残しておこうと書いた次第。

2017-01-27

flexがあるからfloatやclearfixはいらない? んなわきゃ無い

floatやclearプロパティ周りの話題が出るたびに、「flex使えばオッケーじゃん」というような声が散見されるので、「それは違う!」と強く訴えたい、というお話です。

そもそもflexはfloatの代替品ではない

floatプロパティは、それを設定した要素を文字通り"浮かし"て、後続の要素を回り込ませる役割を持っています。

一方のflexの役割は"並べる"のであって、floatのように後続要素を回り込ませる機能は持ちません。

floatを使って要素を並べるのは、本来の用途から少し外れています。そのためclearfixという多少の無理をしていました。その無理のしわ寄せは、clearfixを適用した要素には、after疑似要素を利用できないところに現れます。

なお、要素を並べるには、floatの他に、

  1. display: inline-block;
  2. display: table;とtable-cell;の組

を使うことができます。

段落ちを利用して簡易的にレスポンシブ対応をさせる際、floatを使うと要素の高さの差によって、行頭位置まで落ちてくれないことがあります。inline-blockを使うと段落ちした要素は確実に行頭に落ちます。ただし、inline-blockは改行コードの文字サイズを無視できないため、要素間の間隔を適切にコントロールできない欠点があります。

どの方法も本来の用途から少し外れており、並べる機能に特化したflexの登場はまさに福音と言えます。しかしflexが代替できるのはカラムの分割などの用途に使われるfloatやclearfixに限られます。floatやclearfixのすべての役割を代替することはできません。

clearfixは親要素の背景を表示させるためだけのものでもない。

少なくとも私の場合、clearfixの最大の用途は

「floatの影響を、その親要素内だけにとどめて、親要素の後に続くものが回り込まないようにする。」

という目的を達成するためにあります。

特にレスポンシブデザインが当たり前になってからはこの目的の重要度が上がっています。

floatを画像などに適用した際、幅の狭い画面では画像の下までテキストが回り込んでいたのに、幅の広い画面では画像の横のスペースにテキストが収まり、その下に余白ができる、という状況が頻発するからです。(サムネイル画像と概要テキストで構成される新着記事一覧などはその代表例)

clearfixはHTMLコードへの負担なしにfloatの影響範囲をコントロールできる優れた手法であり、回り込みの機能を持たないflexによって代替されるものではありません。

「flexがあるからclearfixは用済み」という考えは誤りです。

flow-rootへの期待と不安

このclearfixを代替するプロパティが検討されているそうです。

clearfixの必要がなくなる新しいプロパティをW3Cが定義、一部のブラウザでもう使える! | コリス

clearfixのちょっとした欠点である、after疑似要素がclearfixによって埋まってしまう問題を解消してくれるプロパティですが、今のところこの欠点で困ったことが無いので、あまりご利益を感じていないのも事実です。

とはいえ、駆け出しのウェブデザイナーにとってはclearfixのようなややこしいテクニックを理解する手間が省けるのでよいのではないかなあと。遅かれ早かれ、これは普及してくれるんじゃないかと期待しています。

一方、不安な点は名称にあります。floatに関連するものなのに、flow-rootとはこれいかに。float-rootとかなら明瞭ではないかと思うのですが。

名称変更に関する議論のリンク先を見てみると活発な議論が展開されています。

「flow」はCSS Regionsプロパティで使われている。これとは無関係のものに「flow-root」を使うのはかなり混乱するのではないか?「float-container」とかにすることはできない?

という問題提起で、「いや、float-containerもそれなりにややこしいぞ」「そんな変えなくてもよくね?」「変えるんならenclosed-blockとかseparete-blockとか単にnew-blockとかどう?」「flow-blockはいかが?」「block-containerとかは?」

など、多くの案が出されています。

「これFF53とchrome57には実装されるから急いで議論しないとあかんで」

ということですが、まとまるのでしょうか。(現在FFのバージョンは50、chromeは55)

Edgeへの搭載については、IE10がflexプロパティをいち早く実装したらプロパティ名が変わって気の毒なことになってたので、名前が決まってからでいいんじゃないかと思っています。


まあ、少なくともあと3年、長くて5年くらいはclearfixとの付き合いは続くんじゃないでしょうか。非対応ブラウザではほぼ確実にレイアウトが崩れるはずですから、IEAndroidのような非対応ブラウザがなくなるまでは使うことはできません。