Quantcast
Channel: CSSタグが付けられた新着記事 - Qiita
Viewing all 8498 articles
Browse latest View live

ナンの実りもないクソアプリを作った

$
0
0

ナンを咲かせる木を作った

題して「枯れ木にナンを咲かせましょう」

See the Pen 枯れ木にナンを咲かせましょう by Thugumi Ishimaru (@thugumi-ishimaru) on CodePen.

「ナンを咲かせる」ボタンを押したら木にナンが生るクソアプリを作りました。
20個までナンを咲かせることができます。

遊び方

  • 1. 「ナンを咲かせる」ボタンを押す
  • 2. ナンが咲く

以上!!!!!!!!!!!!とっても簡単です!!!!!!!!!!!誰でも遊べる!!!!!!!!!!
そしてクソアプリ!!!!!もちろんなんの役にも立たない!!!!!!!

アプリもクソなのですが、ソースもクソなので何がクソなのかをこちらに解説していこうと思います。
このアプリを反面教師にしていただけたらと思います。

クソアプリのここがクソ

クソ部分その1:何の得もない

この木にナンができたからといって、「......で?」で終わると思うんです。
そう、本当にナンの役にも立ちません。

クソアプリなんだからいいですよね。。。クソなんだから。。。

クソ部分その2:scssが長すぎる

ソースをみてみましょう。

index.html
<divclass="nan"></div>
style.scss
.nan{width:400px;height:300px;position:absolute;top:-100px;&_item{position:absolute;z-index:1;&:nth-child(1){left:0;top:0;}&:nth-child(2){left:100px;top:0;}&:nth-child(3){left:200px;top:0;}&:nth-child(4){left:300px;top:0;}&:nth-child(5){left:0;top:100px;}&:nth-child(6){left:100px;top:100px;}&:nth-child(7){left:200px;top:100px;}(中略)&:nth-child(20){left:200px;top:100px;}

scssファイル読みづら!!!!!!!!
20個以上増やしたくなった時にまたscssに増やさんといけんとか頭痛くない?!
しかもいちいちズラすの?!?!?!?!??!
間に.nan_itemじゃないもの入ってきたら死ぬよ?!?!?!??!

と、色々出てくるんです。
じゃあどうすればいいか、、、今回はscssのみで解決できる方法をお伝えしようかと思います。

解決方法手順その1: ルールを明確にする

間に.nan_itemじゃないもの入ってきたら死ぬよ?!?!?!??!

なぜ死ぬか、nth-child(n)を使っているからです。
と思うのですが、その前にルールを明確にしていないのですね。
ではルールを明確にしてあげましょう。

ということで「.nan以下には.nan_itemしか入れちゃ嫌!!!」とルール化しちゃいましょう。コードで語るのです。
<ul>タグの配下には<li>のみ記述が許可されているのでそのルールを利用します。

  • div.nanul.nanに変更
  • div.nan_itemli.nanに変更
index.html
<ulclass="nan"></ul>
script.js
$('.nan').append('<li class="nan_item"><img src="https://illust-shokudo.com/assets/item/other_00001.png" alt=""</li>');

これで、.nan.nan_itemの間に部外者を入れられなくなりました。

解決方法手順その2: for文でnth-child(n)を生成

20個以上増やしたくなった時にまたscssに増やさんといけんとか頭痛くない?!

大変面倒ですよね。次にこれを解決しましょう。
scssではfor文が使えるので、そちらを使用します。

style.scss
.nan{width:400px;height:300px;position:absolute;top:-100px;&_item{position:absolute;z-index:1;@for$ifrom1through20{&:nth-child(#{$i}){top:0;left:0;}}}}

これでnth-child地獄は脱出しました。
しかし、このままでは配置位置が全て同じになってしまう。。。じゃあどうしよう。。。

次の手順をみていきましょう。

解決方法手順その3: 絶対配置の配置位置をランダムにする

このままでは配置位置が全て同じになってしまう。。。

以下の記事にもあるようにscssではrandom()が使用できます。
これによって、ランダムの数値を当てることができるようになります。
今回はナンの位置を数値で指定していますよね。こちらを使ってみましょう。
https://qiita.com/tonkotsuboy_com/items/909b4073459ecaf7a435

style.scss
.nan{width:400px;height:300px;position:absolute;top:-100px;&_item{position:absolute;z-index:1;@for$ifrom1through20{&:nth-child(#{$i}){left:random(300)+px;top:random(300)+px;}}}}

これで全てのナンをバラバラの位置に表示することができます。

このリファクタを行ったナンの木がこちら

See the Pen 枯れ木にナンを咲かせましょう(リファクタバージョン) by Thugumi Ishimaru (@thugumi-ishimaru) on CodePen.

この実装のメリット

  • scssのみで実装可能
  • scssのソースがスッキリして読みやすくなる

この実装のデメリット

  • 数値はrandom()なので毎回うまく配置されるとは限らない。前提が「この位置に絶対配置するのである」の要件にはそぐわない。

まとめ

クソアプリと共にクソースコードを紹介しました!
クソコードを修正するのに、以下を明確にしています。

  • 枯れ木にナンを咲かせるクソアプリを作った

  • 何がクソか

    • 要素が増えたときに死ぬ
    • 長い
    • 読みづらい
  • scssで以下を修正してクソから少し脱却する

    • ルールを明確にする
    • for文を使用する
    • random()を使用する

枯れ木にナンを咲かせましょう!!!!!!!

おまけ

.nanって命名にしてますが、JavaScriptではNaNという予約語が存在するので、
こんがらがらないように気をつけましょう。
れむさんありとうございます!
https://www.javadrive.jp/javascript/ini/index5.html


HTML テーブルの空セルに斜線を引く方法

$
0
0

テーブルの空セルに斜線を引く方法を紹介します。

まずはテーブルを作成します。

index.html
<table><tr><th></th><th>タイトル1</th><th>タイトル2</th><th>タイトル3</th></tr><tr><td>1</td><td></td><td></td><td></td></tr><tr><td>2</td><td></td><td></td><td></td></tr><tr><td>3</td><td></td><td></td><td></td></tr></table>
style.css
/* table */table{border-collapse:collapse;margin:20px;}tableth,tabletd{width:50px;height:50px;text-align:center;border:1pxsolidblack;}

スクリーンショット 2019-12-23 16.03.22.png
このようなテーブルが作成されます。
それでは、この空のセルに斜線を書いてみましょう。

右上がりの斜線

右上がりの斜線の書き方です。
斜線を入れたいセルにクラスを追加してください

index.html
<tr><thclass="right_up_border"></th><!-- 斜線を入れたいセルにクラスを追加する --><th>タイトル1</th><th>タイトル2</th><th>タイトル3</th></tr>

そしたらCSSを書いていきます。

style.css
/* 右上がりの斜線 */.right_up_border{background-image:linear-gradient(-45deg,/*角度*/transparent49%,black49%,/*斜線の色*/black51%,/*斜線の色*/transparent51%,transparent);}

スクリーンショット 2019-12-23 16.05.29.png
これで斜線を引くことができました!!
簡単です!

右下がりの斜線

次は右下がりの斜線です。これもやり方は同じです

index.html
<tr><thclass="right_up_border"></th><!-- 斜線を入れたいセルにクラスを追加する --><th>タイトル1</th><th>タイトル2</th><th>タイトル3</th></tr>
style.css
/* 右上がりの斜線 */.right_up_border{background-image:linear-gradient(45deg,/*角度*/transparent49%,black49%,/*斜線の色*/black51%,/*斜線の色*/transparent51%,transparent);}

スクリーンショット 2019-12-23 16.15.45.png
できました!!
簡単ですね!

角度の求め方はこちらを参照してください。

底辺と高さから角度と斜辺を計算

まとめ

こんな感じでテーブルの空セルに斜線を引くことができました。
でも多分他にもやり方はあると思うので、アドバイス有りましたらよろしくお願いします。

参考リンク

CSSで斜線を引く方法
底辺と高さから角度と斜辺を計算

CSS擬似クラスnth-of-typeが予想以上に使える件

$
0
0

nth-of-typeとは

擬似クラスnyh-of-typeは、同じ階層にある同じ要素で指定した順番の要素をセレクトすることができる擬似クラスです。
nth-of-type(odd)で奇数番目の要素、nth-of-type(even)で偶数番目の要素、nth-of-type(3n)で3の倍数の要素、など様々な順番でのセレクトが可能です。

class-name:nth-of-type(odd){}class-name:nth-of-type(even){}class-name:nth-of-type(3n){}

これが可能なことで、デザインにもすごい幅が生まれます。
例えば、奇数番目のbackground-colorはblackで、偶数番目のbackground-colorはwhiteとすることで、簡単にシマウマ模様が作れたりなどデザイン性は無限にありそうです。

ぜひ擬似クラスを使用したことのない方は、使用してみてはいかがでしょう。

Chrome拡張機能開発の公式チュートリアルを解説+補足 前編

$
0
0

はじめに

GoogleのChrome拡張の公式が出してるチュートリアルを解説します。
僕なりに分かりやすくなるように、公式の流れに沿って書こうと思います。
ただの翻訳といえば否定できませんが、それだけだとつまらないので、ところどころ補足欲しいなぁ〜て自分が感じたところを付け足していきます。
僕は英語が嫌いなので、僕と同じように英語で書いてあるサイト読むのだりぃ〜って人の役に立てばと思います。

説明に入る前に、僕が以前書いたこの記事

を読んでいただけると少しは理解しやすくなるかと思います。
分かりにくかったら、その記事に載せてる参考文献が分かりやすいので、そちらを見てください。

要約すると、Chrome拡張でやりたいことを実現するには

  • Background
  • Contents Script
  • Popup

の3つの世界を使い分ける必要があるってことです。
理解していただけたら、次に進みましょう。

チュートリアル

さっそく補足ですが、まずは色々なファイルを入れる用のフォルダを作っておきましょう。
場所はどこでも良いです。名前も何でも良いです。
僕は試しに、デスクトップに「testChromeExtension」というフォルダを作りました。
フォルダ作成
ここに、これから作成するファイルや、アイコンの画像などを入れていきます。
それでは作成していきます。

1. マニフェストファイルの作成

「Manifest = 公約」という意味から分かるように、決まりごとを書いていくファイルです。
これがないと拡張機能が作れません。
例えば、

  • この拡張機能の名前は何なのか
  • マニフェストのバージョンは何を使うのか
  • アイコンの画像はどれか
  • PopupのHTMLファイルはどれを使うのか

などをJSONファイルに書いていきます。
ファイル名は「manifest.json」にしましょう。
公式に書いてあるのはこれです↓

manifest.json
{"name":"Getting Started Example","version":"1.0","description":"Build an Extension!","manifest_version":2}

とりあえずこれだけです。
簡単に補足すると、

  • name→ 拡張機能の名前(自分で決める)
  • version→ 拡張機能のバージョン(自分で決める)
  • description→ 拡張機能の説明(自分で決める)
  • manifest_version→ マニフェストのバージョン(これは固定、現在*投稿日現在*は2を書く)

という意味になります。
自分用に書き換えると、こうなります↓

manifest.json
{"name":"Test Chrome-Extension","version":"1.0","description":"これはChrome拡張機能のテストです。","manifest_version":2}

2. アップロード

マニフェストファイルを作り終えたら、最初に作成したフォルダに保存しましょう。
マニフェストファイルを保存

早速これをアップロードしていきます。
ローカルで実行するだけですので、実際に拡張機能のストアに公開するわけではありません。
chrome://extensions/を開きましょう。
アップロード手順

(0. まず、⓪のデベロッパーツールをオンにして、「パッケージ化されていない拡張機能を読み込む」、「拡張機能をパッケージ化」、「更新」の3つのボタンを表示させましょう。)
 1. ①の「パッケージ化されていない拡張機能を読み込む」というボタンを押しましょう。
  英語だと、「LOAD UNPAKED」と書いてあるかと思います。
 2. フォルダを選べるようになるので、最初に作成してマニフェストファイルを入れたフォルダ(②)を選択します。
 3. 選択!(③)

アップロード完了
すると、マニフェストファイルに書き込んだ名前・バージョン・説明・自動生成されたIDが表示されてるかと思います。
アイコンはまだ設定していないので、デフォルトのままですね。
表示されていたら成功です。
表示されていなかったら、ファイル名「manifest.json」やJSONに記入ミスが無いか、manifett_version はちゃんと 2 になっているかを確認してください。

以上がアップロードの手順です。
これからファイルを更新したら、右下のラジオボタンの隣にある更新マークを押せば、更新できます。
反映されない場合は、一旦削除してから再びアップロードするなどを試してみてください。

3. Backgroundファイルの作成

まずは、マニフェストファイルに、「Backgroundのコードはこのファイルに書くよ!」ということ教えてあげる必要があるます。
公式と同じように追加します。

manifest.json
{"name":"Test Chrome-Extension","version":"1.0","description":"これはChrome拡張機能のテストです。","permissions":["storage"],"background":{"scripts":["background.js"],"persistent":false},"manifest_version":2}

BackgroundファイルはJavaScriptで記述します。
ファイル名は何でも良いですが、無難に「background.js」とでもしておきましょう。

それぞれの説明をします。

  • permission→ 使うAPI等を記述します。今回はstrage APIを使用します(詳細は後述)。
  • background→ Backgroundに関しての色々を記述します。
    • script→ Backgroundファイルのファイル名を記述します。
    • persistent→ 永続的に動くか否か。falseにすることで、backgroundファイルが呼ばれた(通信する時)のみ動きます。永続的に動いているとメモリが無駄に消費されてしまうので、falseにすることをお勧めします。

では、実際にBackgroundファイルを作成していきます。

background.js
chrome.runtime.onInstalled.addListener(function(){chrome.storage.sync.set({color:'#3aa757'},function(){console.log("The color is green.");});});

ここで使用するstorage APIは、名前の通りデータを保存してくれるストレージのAPIです。
今後書くContents Scriptファイルに書くことで、わざわざBackgroundにデータを移さなくても、データを保持してくれるみたいです。
ただ、容量がそんなに大きく無いのと、セキュリティがガバガバなので個人情報などは扱わない方が良い、というのが注意点です。

  • chrome.runtime.onInstalled.addListener(function() {});→ 拡張機能がインストールされたときや更新された時に関数内を実行する。
    • chrome.storage.sync.set({color: '#3aa757'}, function() {});→ 先ほど許可したstorage APIの命令です。colorというKeyに#3aa757というValueをセットしています。
      • console.log("The color is green.");→ コンソールに文字を出力します。デバッグなどに使えます。

とりあえずこれらをコピペして、フォルダに保存してください。
スクリーンショット 2019-12-23 16.28.19.png
ファイルが保存できたら、chrome://extensions/で拡張機能を更新しましょう。

すると、「バックグラウンド ページ」というリンクができているかと思います。
拡張機能更新
そのリンクを押すと、Backgroundのデベロッパーツールが表示されます。
background.jsに書いたコンソール出力は、ここで確認することができます。
Background_コンソール
これでBackgroundでChrome拡張を開発することはできました。
ただ、まだ見た目には何も変化がないですが、重要な準備段階です。
後日、残りのチュートリアルの解説をしていきます

おわりに

今回はここまでです。
あと中編と後編を書く予定です。
書けたらリンクを貼ります。

disabled にしたボタンの hover スタイルが消えなくて困った時の対処法

初心者によるプログラミング学習ログ 192日目

$
0
0

100日チャレンジの192日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

192日目は

治安の良いCSSを目指して 〜 平和な世界のために僕たちができること 〜

$
0
0

はじめに

業務でCSSを書くようになってから、いくつかの月日が流れました。
CSSを学び始めた当初は、要素をキレイに横並びにすることすら手こずっていましたが、最近は随分スムーズにデザイン通りのスタイルを書くことができるようになりました。

今日に至るまで、過去の自分が書いたCSSへの後悔の念で眠れない夜や、原因のよくわからない表示崩れの悪夢にうなされる夜もありました。1
これからCSSを学ぶ人、CSSにはあまり詳しくないけどたまに書くよという人にそんな思いをして欲しくない。できたらCSSのことを好きになって欲しい。

そんな思いで自分がスタイルを書く時・レビューをする時に気をつけていることを(自戒も込めて)まとめまてみました。

🤔 良いスタイルってなんだろう?

スタイルを書く時に大切だと考えていることは3点あります。

  • 開発効率
  • デザイン再現性
  • パフォーマンス

開発効率

色々な記事や本でも引用されているCSS Architectureという記事によると、CSS設計のゴールには4つのポイントがあります。

  • Predictable(予測しやすい)
  • Reusable(再利用しやすい)
  • Maintainable(保守しやすい)
  • Scalable(拡張しやすい)

Predictable(予測しやすい)

予測しやすいスタイルとは、ルールが期待どおりの振る舞いをするスタイルのことです。
ルールを追加や更新した場合に意図しない箇所へ影響を与えないこと、つまり影響範囲が明確であることを指します。

Reusable(再利用しやすい)

再利用しやすいスタイルとは、同じようなデザインのUIが登場した時に再コーディングせず、既存のパーツを使いまわせるスタイルのことです。
抽象的で機能が分離している必要があり、そのようなスタイルは制作・運用を効率的にします。
逆に再利用しにくいスタイルの例をあげると、モジュール自体に他のモジュールに影響を与えるmarginがついていたり、クラス名にh1とついていて、同じ見た目のh2が登場した時に使いまわせないスタイルが挙げられます。

Maintainable(保守しやすい)

保守しやすいスタイルとは、新しいコンポーネントの追加・更新・再配置する場合に既存のスタイルをリファクタリングする必要がないスタイルのことです。

Scalable(拡張しやすい)

拡張しやすいスタイルとは、単純に個々のCSSのルールが増える場合だけでなく、サイト・サービス自体が拡大して、複雑になってきても耐えうることを指します。
サイト・サービスが拡大してチームに新しいメンバーが増えた場合の教育コストが低いことも含まれます。

Scalable(拡張しやすい)スタイルにするためには...

「Predictable(予測しやすい)」、「Reusable(再利用しやすい)」、「Maintainable(保守しやすい)」を守ると同時に、コンポーネント設計により関心の分離・カプセル化を行うことが重要だと考えています。
そのためには、styled-componentsEmotionなどのCSS in JSを使用してコンポーネント思考でスタイルを書くこと、BEM、OOCSS、SMACSS、FLOCSといったCSS設計手法を取り入れる事が大切です。

デザイン再現性

デザイン通りの表示になるように、きちんとスタイルが当てられているかを指します。
「デザイン通りの表示」とは、細かくみていくと多くの確認箇所があります。
例えば、下記の場合にも表示が崩れずに、デザインの意図がきちんと反映されているが重要です。

  • すべての対応ブラウザで表示した時
  • ウィンドウサイズを変えた時
  • ウィンドウの縦長/横長表示を変えた時
  • 動的に取得する箇所に様々なパターンのデータが入ってきた時
  • ブラウザの機能でテキストサイズを大きくした時
  • ページを拡大・縮小表示した時

どこまで対応するかの線引きはプロジェクトによって様々かと思います。プロジェクト内で他のメンバーやクライアントと対応範囲の合意を取る事でスムーズに案件を進める事ができます。

パフォーマンス

DOMを必要以上に深くしない

スタイルの計算では、マッチングするセレクタを総当たりで探します。
DOMが多くなれば、それだけ計算コストがかかります。
なるべくシンプルなDOM構造で書くことを意識しましょう。

セレクタを最適化する

ブラウザはセレクタを右から左へ照合する

.boxp{...}

というセレクタの指定があった場合、ブラウザはページ内のすべてのpタグを探し、次にclass="box"をもつ要素を探します。
そのため、キーセレクタ(一番右のセレクタ)とマッチする要素・子孫セレクタが少ないほどパフォーマンスが良いセレクタだと言えます。

要素にはなるべくユニークなクラスを与え、隣接セレクタ(A + B)や子セレクタ(A > B)、全称セレクタ(*)の乱用をしないよう心がけましょう。

ただし、近年のブラウザは以前より処理速度が改善しているため、神経質になりすぎず、開発効率も考慮してセレクタを最適化すると良いでしょう。

不要なスタイルがない

スタイルは必要な箇所に必要なだけ書くことが大切です。
下記を意識することでCSSのサイズが肥大化しないようにしましょう。

  • 使用していないスタイルは削除する
  • ベンダープレフィックスは必要十分なだけ
  • なるべくシンプルなスタイルを書く

レンダリングの負荷が考慮されている

ブラウザがレンダリングする際に要素の位置関係と大きさをを計算するレイアウトの処理後にしてから、ペイントの処理が行われます。
frame-full.jpg

引用: レンダリング パフォーマンス | Web | Google Developers

アニメーションをつける際は、なるべく処理順がフローの後のものを動かす方がレンダリングの負荷は軽くなります。
例えば、要素の位置を動かす時に、topleftの値をいじるより、transform: translate();を使用する方がパフォーマンス向上には有利です。
各CSSプロパティがどの段階で処理されるのか知りたい場合は
CSS Triggersが詳しいです。
また、will-changeプロパティを使用すると、要素にどのような変更を加えるかを前もってブラウザに知らせることができます。適切に使用することでパフォーマンスの改善が期待できます。
参考: MDN Web Docs | will-change

🤢 スタイルアンチパターン

自分がコードレビューをするときに「mustで直してね」とコメントを書きがちな具体事例を紹介します。
もちろん、最適なスタイルの書き方はプロジェクトの性質によって変わってくる部分もあると思います。
プロジェクトのコーディング規約がない場合やこれから作るという場合の参考になれば幸いです。

!importantを使用している

!importantを指定すると優先度が最強になってしまいます🤯
!importantを指定したスタイルを上書こうとすると、セレクタで詳細度を高めた上で!importantをぶつけるという、血を血で洗う戦いが始まってしまいます。
!importantは切り札にして諸刃の剣...、これが繰り返されると地獄を見る羽目になるのでやめましょう。

ただ、既存のソースをいじれない場合や、外部ライブラリのスタイルを上書きしたいなど、どうしても!important使わなければならないという場面に出くわすこともあるかもしれません。

その場合は、後世のために「なぜ!importantなしではダメだったのか」をコメントに残すことをオススメします。

idにスタイルを当てている

idは1つのページで1度しか使用できません。
そのためidセレクタを使用すると、再利用することができなくなってしまいます。
また、idセレクタはクラスセレクタより詳細度が高いです。詳細度が複雑になると詳細度の管理コストが発生します。
結果として、予測しづらく、再利用しにくいCSSになってしまいます。

不要なスタイルが存在する

不要なスタイルはCSSのサイズを無意味に増やしてしまうし、見通しも悪くなります。
また、スタイルが継承されることで、その子孫要素にも不要なスタイルの影響が出てしまいます。
それにより、打ち消しのスタイルが増えたり、依存関係がわかりにくくなってしまいます。
不要なスタイルが混入する原因としては、「デザインデータのCSSからコピペしてきた」「色々試してた結果残ったままになっていた」というものが経験上多いです。
期待通りの表示になった後、不要なスタイルが紛れていないか再度確認すると良いでしょう。

valueが0の場合に単位が指定されている

marginpaddingborderなどを打ち消す時に0を指定することがありますがCSSの仕様でvalueが0の時は単位がoptionalになります。
とても細かいのですが、不要なものは書かないのが原則なので0の時は単位を書かないようにしましょう。2

line-heightに単位が指定されている

line-heightには単位を使用せず相対値で書く方がよいとされています。
理由は2点あります。
1つ目の理由は、スタイルは親から子に継承されるので単位ありの絶対値で指定すると、子要素で打ち消すスタイルを書かなくてはならない場合があります。
デザインでは「1.2」や「1.5」など、行間が統一されて決められていることが多いため、相対値で指定する方が打ち消さずに済むことが多いです。

2つ目の理由はブラウザの機能で文字を大きくした時に、line-heightの高さより文字の大きさが大きくなって、表示が崩れることがあるためです。

marginが相殺されている

marginには相殺の性質があります。
相殺が起きている要素間に別の要素が増えた場合や要素を再配置・再利用する場合にうまくいかないことが多いです。
再利用性・メンテナンス性が低くなってしまう原因になるため、相殺が起きるスタイルはあまり推奨しません。
マージンの相殺 | MDN

🤔 気をつけたいスタイル

「絶対だめ」というわけでもないですが、開発効率やデザイン再現性観点で注意したいスタイル指定についてまとめました。

heightが決め打ちで指定されている

要素のheightを決め打ちで指定する場合、動的なテキストが長くなる場合がないか・画面サイズが変わって中に入るテキストが折り返す場合がないかに注意しましょう。
また、ブラウザ側でテキストサイズを大きくした時に表示崩れが起きないかも確認すると良いでしょう。

marginの値がマイナス

値がマイナス値のmarginはネガティブマージンやマイナスマージンと呼びます。
多用するとmarginの計算が複雑になり、デザイン崩れの原因になりやすいです。
ネガティブマージンを使わなくても実現する方法がないか考えて、ここぞという時以外にはなるべく使用しないのが吉です。

Flexbox or Grid Layout以外での横並び・上下中央寄せ

一行の横並びはFlexbox、複数行の横並びはGrid Layoutで書くと、行数やDOMの深さが少なく済むことが多いです。
また、Flexbox or Grid Layoutを使うことでレスポンシブ対応もしやすくなります。

position: absolute;を指定している要素の直前の親にposition: relative;の指定がない

position: absolute;はpositionプロパティのstatic以外の値が指定されている親要素を基準に位置が決まります。基準としたい要素にposition: relative;を指定して、その直下にposition: absolute;要素を置くことで依存関係がわかりやすくなり、「あれ?absoluteなアイコンが、気がついたらいないぞ?」ということを防止できます。

👼 オススメスタイルTips

marginの向きを揃える

上で述べたmarginの相殺を防止するために、marginの向きを揃えることはとても有効です。
margin-top/leftで揃えるかmargin-bottom/rightで揃えるかは、個人的にはプロジェクト内で統一されていればどちらでもいいかなと思います。

font-sizeの指定はrem

font-sizepxで指定すると、ブラウザの機能でテキストサイズを大きくしようとしても変更できないため、アクセシビリティを考慮するとイマイチです。

また、SPとPCで基準となるfont-sizeを変えたいという場合やSPの時だけ画面幅に応じてfont-sizeを変えたいという場合もあるでしょう。

htmlタグにベースのfont-sizeを指定して、各要素にはremで指定をするとfont-sizeを扱いやすく書くことができます。

html{font-size:62.5%;@mediascreenand(max-width:768px){font-size:calc(100vw/375*10);}}

全要素にbox-sizing: border-box;を指定する

box-sizing: border-box;を指定すると、widthheightで指定する幅と高さにpaddingborderの値が含まれるようになります。
これを全要素に指定することで幅と高さの算出方法をすべてのスタイルで統一する事ができます。
また、デザインデータを作成する際に、ボーダーあり/なしのパターンで高さを揃えるために、要素の内側にボーダーをつける事が多いらしいです。
box-sizing: border-box;の指定によって、デザインデータからCSSにスタイルを起こしやすくすることもできますね。

ressなどbox-sizing: border-box;の指定が初めから含まれているリセットCSSを使うか、そうでない場合はベースのスタイルとして自分で追加しておくとベターです。

*,::before,::after{box-sizing:border-box;}

便利なツールを利用する

人間は不完全な生き物なので、ツールでできることは任せてしまいましょう。
見落としを防ぐだけでなく、実装やレビューの工数を削減にも繋がります。

便利なツールたち

  • stylelintでルールを指定する
  • stylelint + Prettierでフォーマットする
  • Autoprefixerで自動的に過不足ないベンダープレフィックスをつける
  • reg-suitでビジュアルリグレッションテストを行い意図しない表示の変更を検知する

👮‍♂️ 最後に

1つ1つは細かいことですが、その積み重ねが平和なCSSの世界を築いていくと信じています。
私もまだまだ勉強中なので頑張ります。
世界が平和でありますように🤗


  1. イメージです。 

  2. ただしflex-basisはIE11で単位が必須なため、flex-basis: 0%とかく必要がります 

[ライブコーディング]JavaScriptでモンテカルロ法シミュレータを作る

$
0
0

モンテカルロ法とは

ルーレットの必勝法とか言われる掛け方の法則。
実際にカジノで実践するには紙とペンが必要になるので、それをWebアプリ化したかった

言い訳

事前準備のない、ガチのライブコーディングをやりたかった。

そして、
フレームワークとか、IDEだとか、ネーミングとか
一切気にせず
ただただ頭に浮かんだコードを書いて、htmlとjscssで楽しく遊ぶことを意識した

結果

とんでもないコードができあがった。

index.html
<!DOCTYPE html><htmllang="ja"><head><metacharset="utf-8"/><title>モンテカルロ法シミュレーター</title><linkrel="stylesheet"href="index.css"></head><body><h1>モンテカルロ法シミュレーター</h1><div>ゲーム数: <spanid="js-game"></span></div><div>数列: <spanid="js-sequence"></span></div><div>
      bet: <spanid="js-bet"></span></div><div>
      status: <spanid="js-status"></span></div><div>ベット総額: <spanid="js-total-bet"></span></div><divclass="controller"><buttonid="js-win">勝った</button><buttonid="js-lose">負けた</button></div><script src="index.js"></script></body></html>
index.js
import$from'jquery';// ゲームの回数letgame=1;// 数列letsequence=[];// ベット数letbet=0;letstatus='はじまり'constgetSequence=(game)=>{if(game===1){return[1,2,3];}else{returnsequence;}}constgetBet=()=>{constfirst=sequence[0];constlast=sequence[sequence.length-1];returnfirst+last;}// 勝ったときの処理$(document).on('click','#js-win',()=>{game++;sequence.pop();sequence.shift();// 終了かどうかif(sequence.length<=1){status='おわり'}// ゲーム数表示$('#js-game').html(game);// 数列表示sequence=getSequence(game);$('#js-sequence').html(sequence.join(','));// ベット表示bet=getBet();$('#js-bet').html(bet);// ステータス表示$('#js-status').html(status);})// 負けたときの処理$(document).on('click','#js-lose',()=>{game++;sequence.push(bet);// ゲーム数表示$('#js-game').html(game);// 数列表示sequence=getSequence(game);$('#js-sequence').html(sequence.join(','));// ベット表示bet=getBet();$('#js-bet').html(bet);// ステータス表示$('#js-status').html(status);})// ゲーム数表示$('#js-game').html(game);// 数列表示sequence=getSequence(game);$('#js-sequence').html(sequence.join(','));// ベット表示bet=getBet();$('#js-bet').html(bet);// ステータス表示$('#js-status').html(status);

感想

忘れかけていた何かを思い出した。

ライブコーディングの様子:
https://youtu.be/HJR_iUAMLWA


クリスマスツリーをCSSで作ってみた

$
0
0

はじめに

アドベントカレンダーといえばクリスマス。
クリスマスといえばツリー。
ということで、とってもありきたりですがクリスマスツリーをCSSで作ってみることにしました。

用意するもの

  • もみの木
  • 電飾
  • てっぺんの星
  • オーナメント

作ってゆく

もみの木

まずはもみの木から。これがないと始まりませんからね。
何となくもみの木は3段のイメージでいたんですが、画像検索してみるとそんなことないんですね。
いいんです。気にしません。borderを使っていい感じの三角形を作って、よしなに重ねていきます。
幹の部分もborderを使って台形を作り背面に置きます。

See the Pen tree by sasakiy (@sasakiy0819) on CodePen.

電飾

とにかくもう何が何でもキラキラ光らせたかったので、オーナメントの前にこれを作ります。
作り方は簡単。適当なサイズの円を作り、アニメーションを使ってbox-shadowで光彩を加えていきます。

See the Pen light by sasakiy (@sasakiy0819) on CodePen.

てっぺんの星

まず、五角形の星型の内角の和は180°になるということを思い出すところから始めます。
正五角形の星型にするには頂点の角度は36°にしたいところなので、36°-36°-108°の三角形を3つ用意して、それらを重ねて正五角形を作ります。
これに黒丸背景を重ねればサッポロビールのロゴの完成ですね。

See the Pen star by sasakiy (@sasakiy0819) on CodePen.

オーナメント

本当は杖とかヒイラギの葉とか作りたかったんですが、断念しました。
プレゼントの箱を用意することにします。

See the Pen ornament by sasakiy (@sasakiy0819) on CodePen.

組み立てる

用意したパーツたちをひたすら並べて組み上げていきます。
アクセントにアニメーションで雪を降らせてみたりします。

See the Pen merged by sasakiy (@sasakiy0819) on CodePen.

まとめ

CSSってなんでもできますねー。
業務ではなかなか機会のなさそうな使い方ですが、きっとどこかで何かしらの約には立つのではないかと思います。

React-SpringのHooksベースAPIでブラウザアニメーションを基本から極めよう!

$
0
0

🎄メリークリスマスイブ!🎄この記事は、React-Spring1というアニメーションのライブラリを紹介する NTTテクノクロス Advent Calendar 2019の24日目の記事です。23日目は@yuitomoさんの記事、明日25日最終日は@korodroidさんの記事です。


2019年、令和初の年末も押しせまってまいりましたが、みなさん如何おすごしでしょうか? NTTテクノクロスの上原と申します。React/Gatsbyを用いた社内キュレーションサイトの構築や運用などを担当しています。当社では上記含め、SPAの開発にReactが採用されるケースも比較的多く、社外ブログにReactVRの記事を書いたり、去年のアドベントカレンダーイベントではGatsbyの記事「Reactベース静的サイトジェネレータGatsbyの真の力をお見せします」を書いたりしております。

はじめに

Webサイトの要所にあるアニメーションって、効果的に使えばかっこいいですよね。

でも、アニメーションって作るのは結構難しいです。私もですが、今まで修得を試みたものの挫折した経験がある方もいらっしゃるのではないかと思います。まあ出来合いの画面ライブラリでなんとかなっちゃう時も少なくないわけですが、シュッとした動きが思い通りにつけられたらなあ、とも常々おもっておりました。

そんな昨今、React-SpringというモダンなReact用のアニメーショライブラリ2を見つけて、Reactであれば! Hooksであれば!理解できそうなので(理解したとは言っていない)、解説記事を書いてみました。

対象読者

React経験者の方。Hooksの経験があるとなおよい。CSS Transitionとかの経験は不要である。

この文章の位置付け

本文書はreact-spring公式ドキュメントの代替を目指してはいません。ただ、公式ドキュメントはおそらく要点を絞りこみすぎていて、他のアニメーションライブラリやイージングライブラリの使用経験がないと、いきなり読みくだし理解することは難しいと感じました。本書では公式に抜けている「概念の説明」に重点をおいて、導入時に併読することで有用であることを目指しています。

本文書は筆者が調査したり類推した内容を含んでおり、間違いを含む可能性があります。問題がありましたら、ご連絡いただけますと幸いです。

アニメーションとは何か

最初にアニメーションの基本について説明します。不要であれば「react-springの紹介」まで読み飛ばしてください。

「アニメーション」とは、広義には絵を初めとする本来動かないものを動くように見せる映像表現のことです。ブラウザで表示しているページがスクロールしたり、ブラウザウィンドウをドラッグして移動させる、なども大きな意味では立派なアニメーションです。アニメーションGIFだってアニメーションです。

その部分集合として、react-springが扱う「アニメーション」とは、「DOMで表示されている画面上のオブジェクトの色や属性などが連続的に変化する」というものです。DOMアニメーションとCSSアニメーションの両方を含むものと考えてください。動画やGIFアニメの再生は対象外です。

「連続的に変化する」とはどういうことか

一般に、CSSやDOMをJavaScriptから更新すると、その設定内容は「瞬時に」「離散的に」変化します。途中経過がないのです。こんな感じです。

●            →           ◯

     一瞬で変化する

厳密には一瞬ではないでしょうが、ブラウザはさまざまな再計算やレンダリングを行い「最終結果」を表示するための処理を一目散に行います。

これに対してreact-springの意味で「アニメーション」として表示することは、以下のように表示するということです。

● → ● → ● → ..◯ → ◯ →◯ → ◯

   細かい単位(1/60秒ごとに)で変化する

1/60秒ごと(60Hz)というのは一般的なPCやMacでのリフレッシュレート、すなわち画面変化が物理的に視認できる最短の時間間隔です。この間隔でフレームバッファからディスプレイに情報が転送されるので、この単位よりも細かく画面を変化させることはできません。ちなみに、Oculus RiftやHTC ViveなどのVRヘッドマウントディスプレイでは、リフレッシュレートは90Hzであり、どんなディスプレイでも60Hzであるわけではありません。

連続的変化を表現するための方法

表示する画像をパラパラ漫画のように、たとえば60枚の画像を用意して1秒間に切り替えれば1杪分のアニメーションを表現できます。しかし容量は大きくなるでしょうし、前述のようにリフレッシュレートが異なるケースがあることも考えれば望ましくありません。

なので、一般にブラウザのUIのアニメーションでは以下のようにします。

  1. ブラウザ内の表示要素の「動き」の元になるものとして、DOM要素の位置大きさ透明度などに使用する実数値をピックアップします。
  2. その値を、時刻を引数とする関数値と考えます
  3. なんらかの方法でその関数を実装します。たとえば、
    • 現在の値と最終値を与え、その間を補完する値を返す関数を生成する
    • その値変化に対応する、JavaScriptの関数を定義する
  4. 1/60間隔で以下の処理を実行する
    • 上記関数のその時点での値を決定し、
    • DOMの属性をその値で更新する

このように関数もしくは計算式で定義すれば、間隔が60Hzであろうが120Hzであろうが一般的に定義できます。あるいはCPUが重くて処理が表示においつかなかった場合でも、更新を間引いて間隔を長くすることでなめらかさは劣るとしても動きとしては正しいアニメーションを表示することができます。

と、言葉では簡単そうですが、問題はこの関数を定義するのが難しいことです。単純な一次関数では自然な動きになりません。その問題を解決する適切な関数を生成する機能をもっているのがアニメーションライブラリであり、イージングライブラリ3です。

react-springの紹介

ということでここからが本題です。react-springは、DOMアニメーションやCSSアニメーションを行うためのReactライブラリです。以下の特徴をもっています。

  • 💐宣言的アニメーション

    • 最終的な姿や「こうなっているときこうする」といったルールを設定で指定するだけでアニメーションを表現します。「なにかのメソッドを呼び出したらアニメーションを開始する」とかはありません。「アニメーションのタイムラインのx杪目を実行中」みたいな概念もありません。Reactが「宣言的UI」であるのと同様に、宣言的にアニメーションを指定します。
  • 💐物性ベースのタイミング指定

    • 従来のアニメーションライブラリだと、アニメーションのタイミングや移動速度などは、継続時間とベジエ曲線(イージング関数)で指定するのが普通でした。これに対してreact-springでは慣性、摩擦力、張力をもった物理的な性質(物性)でタイミングを指定します。
      どういうことか?
      • 張力が強いバネなら、シュと戻り、摩擦力が高いと、ジワーっと移動します。慣性が大きいと、ふんぬっ、ぬお〜、と一拍おく感じで物体が動きはじめます。張力が高いと、ビッビッと力強い動きをします。そういう感じに、コンピュータ上の図形の変化でも、物理的なモノがあるかのような動きをさせるのです。
      • 移動時間を2.5杪にするか、1.5杪にするかなどは、天才アニメーターじゃないんだから常人には考えても答えなんかわかりません。バネのようにビョーンなのか、ハチミツのようにニチャーっと動くのか、という風に直感的に指定します。
      • Appleの元UI-Kit開発者、Andy Matuschakは以下のように言っているそうです
        継続時間とイージング曲線を引数とするアニメーションAPIは、継続的でなめらからなインタラクティブ性に根本的に反するものである。
  • 💐React Hooksベース/TypeScript対応

    • HooksベースのAPIが使用できます4。当然TypeScirpt対応です。
  • 💐React Native対応。

    • Webだけではなく、react-native, react-native-webの開発をサポートします。

やってみようReact-Spring

            ⚠注意!⚠
react-springのバージョンは、原稿執筆時の最新stableのv8ではなく、次期版であるv9ベースのものを使用してください。v8には特にTypeScriptの型定義に致命的な問題があります。「yarn add react-spring@next」 でインストールできます。

react-springのアニメーションプリミティブ一覧

react-springのHooksベースAPIの基本的なプリミティブには以下があります。

  • (1) useSpring Hooks
    • 1つの設定(config)のもとで、1つもしくは複数のアニメーション値(アニメーション的に変化する数値)を束ねるSpringオブジェクトを生成する。
  • (2) useSprings Hooks
    • 複数の設定(config)に対する複数のSpringオブジェクトを生成する。
  • (3) useTrail Hooks
    • 後続のものが先行するものに追随するような、複数のアニメーション値を定義する(Trail)。
  • (4) useTransition Hooks
    • 表示コンポーネントを別のコンポーネントに「切り替える」ときのアニメーション効果(Transtiion)を定義する。
  • (5) useChain Hooks
    • Spring,Trails,Transitionなどによる効果を連鎖的に実行する。

これらが、react-springにおけるアニメーション表現のための基本的な枠組みになります。それぞれの詳細については後述します。

アニメーションのAPIの概観

APIの個別の説明に入るまえに、useSpringを例にとって、react-springにおけるHooks APIのおおまかなイメージをまず説明します。
ureSpringはreact-springのプリミティブの中でもっとも基本的なものです。
useSpringのAPIは以下のようなHook関数です。

// (A)useSpring:({...アニメーション値:目標値,...configs})=>アニメーション値// (B)useSpring:(()=>{...アニメーション値:目標値,...configs})=>[アニメーション値,トリガ関数]

つまり2つのオーバーロードされた関数があって、引数がオブジェクトか関数かによってそれぞれ

  • (A) アニメーション値
  • (B) アニメーション値とそのトリガ関数

をそれぞれ返します。この二種類は、コントロールの方法が違います。
以降、ここでいくつか出てきている用語を説明します。

【用語説明】アニメーション値(AnimatedValue)

react-springによるアニメーション処理における最も基本的で重要なプリミティブがアニメーション値です。これは時間経過によって変化する値です。「キーとその値」というオブジェクトの形をしていて、useSpringなどのHook関数の返り値として得ることができます。
アニメーション値は以下の特徴を持っています。

  • アニメーション値は、後述の「アニメーション化されたコンポーネント」でのみ使用できる。
  • useStateが提供するような状態値を保持する。違いとしては
    • useStateが返却するセッター関数で可能であるような「前の値から次の値を設定」などはできない。
    • requestAnimationFrameのタイミングで勝手に変化する。
  • アニメーション値は文字列や配列であってもよい。変化を計算する以上、本質的には一つ一つのnumberに対応するが、その表現として"18pt"とか単位がついてもいいし、"scale(3.0)"や"translate3d(0px,0,0)"みたいに文字列とに埋め込まれていてもいい。"red","green"、角度などDOMの修飾に使用できる多様な値を扱える

アニメーション値によるアニメーションをトリガし開始するには、主に3つの方法があります。

  1. (A)の引数のアニメーション値を変化させる。変化させると、その値に向かってアニメーションの変化が開始される。
  2. (B)の呼び出し結果に含まれる「トリガ関数」で新しい値を引数にして呼び出す。たとえば、
    setAnimValue({key: value});
    のように、アニメーション値のキーと値を選択的に指定できる。
  3. (A),(B)いずれの場合でも、後述configのfromプロパティを設定する。immidiate: falseでなければ、from値とto目的値に差があれば、マウントされた時点でアニメーションのトリガがかかる。

【用語説明】アニメーション化されたコンポーネント(Animated Component)

「アニメーション値」の実体は、react-springライブラリが生成する、状態をもったオブジェクトなのですが、これをそのままコンポーネントのスタイル指定に与えることはできません。仮想DOMが理解する通常の数値や文字列に変換する必要があるのですが、アニメーション値の方を変換することはしません。その代りに、それを受け取って使用する側のコンポーネントの方を変換します。何を言ってるかというと、たとえば、

constMyComponent=({fontSize})=>(<divstyle={{fontSize:fontSize}}>HelloWorld</div>
);

こんなコンポーネントのstyle属性としてのfontSizeプロパティにアニメーション値を与えたいなら、

import{useString,animated}from'react-spring';constaprops=useSpring({fontSize:'150%'})constAnimatedMyComponent=animated(MyComponent);// ★...<AnimatedMyComponentstyle={{fontSize:aprops.fontSize}}/>
<!--もしくは<AnimatedMyComponentstyle={aprops}/> -->
-->

上記の★のところで、関数animatedにコンポーネントを渡して変換をかけます。ここで得られる「AnimatedMyComponent」は、プロパティにアニメーション値が来たときに、明示的にrequestAnimationFrameを呼んだりしなくて、そのアニメーション値に従ったアニメーション表示を行うコンポーネントになります。これを本文書では「アニメーション化されたコンポーネント」と呼びます1

div,span,imgなどについては、あらかじめアニメーション化されたコンポーネントが用意されています。

コンポーネント意味
animated.divアニメーション化されたdivコンポーネント
animated.spanアニメーション化されたspanコンポーネント
animated.imgアニメーション化されたimgコンポーネント
animated.svgアニメーション化されたsvgコンポーネント
animated.h1,h2..アニメーション化されたh1,h2,..コンポーネント

【用語説明】config

configはHooksに与える設定用オブジェクトです。

= useSpring({ここにキー:バリューで指定})

主なキーには以下があります。

プロパティ名説明
任意num/string目的値。キーが既定義のものに被らなければ、toで指定する目標値として扱われる。
fromobjアニメーション値の初期値。オプション。トリガされる前に使用される値。
toobj/fn/array(obj)アニメーション値が収束する目標値。
delaynumber/fn開始時の遅延(ms)。オプション。引数にkeyをとる関数を与えると、複数のアニメーション値を設定することができる(fnについては以下同様)。
configobj/fn慣性、摩擦力、張力などの物性を指定。既定義の物性もある(config.default/config.gentle/ config.wobbly/config.stiff/config.slow/config.molasses)。オプションであり指定しないとconfig.defaultが使用される。
refReactのref後述のuseChainで連鎖的に実行するアニメーションの一環として動作させる。

API説明

(1) useSpring Hook

ureSpringはreact-springのプリミティブの中でもっとも基本的なものです。
1つまたは複数のアニメーション値をハンドリングします。

useSpring によるアニメーションの例(SampleA, SampleB)

spring.gif

上記は、1行目がSampleSpringAというコンポーネント、2行目がSampleSpringBというコンポーネントで実装しています。見た目は同じですが、処理がことなります。
SampleSpringAは、useSpringに目的値のプロパティを与え、Springを得ます。
SampleSpringBは、useSpringに初期値を返す関数を与え、Springとトリガ関数を得ます。

useSpringコード例(SampleSpringA.tsx)

以下SampleSpringAのソースコードです。

SampleSpringA.tsx
importReact,{useState}from"react";import{useSpring,animated}from"react-spring";constSampleSpringA=()=>{// (A)const[enter,setEnter]=useState(false);constspring=useSpring({fontSize:enter?"48pt":"24pt",color:enter?"red":"green"});return(<animated.divstyle={spring}onMouseEnter={e=>setEnter(true)}onMouseLeave={e=>setEnter(false)}>HelloReactSpring</animated.div>
);};exportdefaultSampleSpringA;

enterというstateを間接的にSpringに参照させ、そのstateを変化させることで、目的値が変化します。すなわち、stateの更新と引き続くrenderの呼び出しのタイミングで、アニメーションのトリガがかかり、アニメーションが進行します。

useSpringコード例(SampleSpringB.tsx)

以下はSampleSpringBのソースコードです。

こちらではstateを介在させる必要がなく、useSsringに関数をわたすことで、トリガ関数が返ってくるので、トリガ関数を任意のイベントハンドラ等から呼び出すことでアニメーションの進行がはじまります。

SampleSpringB.tsx
importReactfrom"react";import{useSpring,animated}from"react-spring";constSampleSpringB=()=>{// (B)const[spring,set]=useSpring(()=>({fontSize:"24pt",color:"green"}));return(<animated.divstyle={spring}onMouseEnter={e=>set({fontSize:"48pt",color:"red"})}onMouseLeave={e=>set({fontSize:"24pt",color:"green"})}>HelloReactSpring</animated.div>
);};exportdefaultSampleSpringB;

(2) useSprings Hook

複数の設定(config)に対する複数のSpringオブジェクトを生成します。
同種のアニメーションを行う一連のアニメーション化されたコンポーネントを生成することができます。

useSpringsによるアニメーションの例

springs.gif

useSpringsコード例(SampleSprings.tsx)

springの列のインデックスを引数とするコールバック関数で、それぞれのspringの設定をします。
トリガ関数もspringの列のインデックスを引数とする関数を指定します。

SampleSprings.tsx
importReact,{useState}from"react";import{useSprings,animated,config}from"react-spring";constSampleSprings=()=>{constmsg="Hello React Spring";const[springs,set]=useSprings(msg.length,(idx)=>({// idxによって異なる設定をしてもよい。config:config.wobbly,fontSize:"24pt"}));return(<divstyle={{fontSize:"24pt"}}>{springs.map((item,idx)=>(<animated.spanonMouseEnter={e=>set(i=>(i===idx?{fontSize:"48pt"}:{}))}onMouseLeave={e=>set(i=>(i===idx?{fontSize:"24pt"}:{}))}style={{verticalAlign:"top",...item}}>{msg[idx]}</animated.span>
))}</div>
);};exportdefaultSampleSprings;

(3) useTrail Hook

後続のものが先行するものの変化に追随するような、複数のアニメーション値のリストを定義する(Trail)。
マウストラッキングアニメーションのようなものが簡単に定義できます。

useTrailによるアニメーションの例

trail.gif

useTrailコード例(SampleTrail.tsx)

SampleTrail.tsx
importReact,{useState}from"react";import{useTrail,animated,config}from"react-spring";constSampleTrail=()=>{constmsg="Hello React Spring";const[{x,y},setXY]=useState({x:0,y:0});consttrails=useTrail(msg.length,{config:config.gentle,left:`${x}px`,top:`${y}px`,position:"absolute"});return(<divstyle={{width:"100%",height:1000,fontSize:"24pt"}}onMouseMove={e=>{e.persist();setXY({x:e.clientX,y:e.clientY});}}>{trails.map((trail,idx)=>(<animated.spanstyle={{...trail,paddingLeft:idx*23}}>{msg[idx]}</animated.span>
))}</div>
);};exportdefaultSampleTrail;

(4) useTransition Hook

表示コンポーネントを別のコンポーネントに「切り替える」ときのアニメーション効果を定義する。
以下を一手にまとめてやってくれます。

  • これから表示しようとするコンポーネントをDOMに新たにマウントとする処理
  • 新しくマウントしたコンポーネントに対するアニメーションの実行
  • 新しくマウントしたコンポーネントによって、置き換えられてしまうコンポーネントをDOMからアンマウントする処理
  • 置き換えられてしまうコンポーネントのアンマウント時のアニメーションの実行

一般に、コンポーネントを「切り替える」操作として、「古い方をアンマウントと新しいののマウントする」を同意に行うのが自然なのですが、アニメーションとしては、アンマウントされる方が消えていくアニメーションと新しい方が表われてアニメーションは、時間的重なりをもって動かないとそれらしくありません。なので、useTransionの返り値は高々2要素の配列であり、消えていくコンポーネントは時間差をもってアンマウントされます。

例と説明は都合にて割愛します。(後で追記するかも)

(5) useChain Hook

Spring,Trails,Transisionなどによる効果を連鎖的に実行する。

  • Springなどのアニメーション値を作成する際のconfigに、refプロパティを指定し、useRefの結果を組込むすることで、useChainがrefを使ってトリガ関数の役割りを果してくれるようになります。逆に言えば、ref属性を組込むとトリガ関数経由ではコントロールできなくなります。
    • このせいか、useSpringの(B)「アニメーション値とそのトリガ関数」のパターンのものに対してはuseChainは機能しません。

useChainによるアニメーションの例

refを準備し、制御下における部品に組み込み、chainで繋げます。

chain.gif

useChainコード例(SampleChain.tsx)

SampleChain.tsx
importReact,{useState,useRef}from"react";import{useSpring,useChain,animated,config}from"react-spring";constSampleSpring=({ref})=>{const[enter,setEnter]=useState(false);constref1=useRef();constref2=useRef();constspring1=useSpring({fontSize:enter?"48pt":"18pt",ref:ref1});constspring2=useSpring({fontSize:enter?"48pt":"18pt",ref:ref2});useChain([ref1,ref2]);return(<divstyle={{textAlign:"center"}}onMouseEnter={e=>setEnter(p=>!p)}onMouseLeave={e=>setEnter(p=>!p)}><animated.divstyle={spring1}>HelloReactSpring</animated.div>
<animated.divstyle={spring2}>HelloReactSpring</animated.div>
</div>
);};exportdefaultSampleSpring;

おわりに

ということで、react-springによる最先端Webアニメーション技術のサワリを紹介しました。
今回、紹介したのは、react-springの機能の一部ですが、主要なところはカバーしたつもりです。
本書のデモでは主に、fontSizeという地味な属性を変化させましたが、transform: scale, rotateなどのプロパティを変化させたり、SVGを使用すると複雑で派手なアニメーションを行うことができ、基本は同じです。
公式サイトには他に多数のデモが掲載されていますので参考ください。

もうアニメーションも怖くない! かも!

参考リンク

本文書のサンプルコードはこちらもしくはこちらにあります。


  1. ロゴ画像はhttps://user-images.githubusercontent.com/619186/51572411-7e04a880-1e8c-11e9-802c-251f150a1e69.gifより引用 

  2. GitHubスター数15.4k(2019年12月現在)となかなかの人気なのではないかと思います。 

  3. 世界一わかりやすい「イージング」と、その応用」などが参考になります:  

  4. HoCやRender PropsベースのAPIもあります。
     

[Angular] 親コンポーネントから子コンポーネントのスタイルを変更しようとしたらハマった

$
0
0

やりたかったこと

親コンポーネントで定義したスタイルを子コンポーネントへ反映させたかった。

parent-compomemt.html
<parent-compomemt><child-compomemtclass="double-border"></parent-compomemt>
child-compomemt.html
<inputtype="text"class="input">

下記のような定義ではスタイルは反映されない。
そもそも親から子のスタイルを変えるのはお作法的にも悪いとのこと。

parent-compomemt.scss
.double-border {
  .input {
    border: double;
  }
}

解決策

:hostを使用して、子コンポーネント側で定義すれば良い。

child-compomemt.scss
:host.double-border {
  .input {
    border: double;
  }
}

CSSにおけるシャドウ効果の影

$
0
0

対象読者

  • 「このシャドウはCSSで再現可能かな?」とお悩みのデザイナーの方
  • 「このシャドウどうやってCSSで再現しよう、、」とお悩みのフロントエンドの方

注意

  • Sass芸(Sassの@for等を利用して、複雑な形を再現したりする行為)ではなく、無理なく使える範囲を狙います
  • IEには疲れたのでこの記事中では存在しないことにします
  • 作例はPug + Stylusで作成しています

htmlの要素にシャドウをつけたいという欲求

に対する一番シンプルな答えは、CSSのbox-shadowプロパティですね。
これを利用することで、要素のフレームの周囲にシャドウ効果を追加できます。

ただ、これはCSSの中でも扱いが難しいプロパティかと思います。
苦い顔をしてしまう方も多いのではないでしょうか?

box-shadowの憂鬱

というのも、Adobe XDなど、デザインツールは矩形でなくとも様々な効果を設定することができるためです。

一方のCSSはボックスモデルに基づき、矩形の領域をベースにスタイリングを行いますから、デザインの再現に無理が発生してきます。

その際、box-shadowは、同じくボックスモデルの周囲を装飾するborderと比べ、左右上下での調整が効きにくく、綺麗に表現するには工夫が必要な場面が出てきがちです。

CSSにおけるシャドウ効果は一筋縄ではいかない、、、そう、があるということです。
※個人の感想です

この記事では、そんなシャドウ効果の一端をご紹介します。

Lv.1 矩形の要素

box-shadowを設定するのみです。

See the Pen Lv1.box-shadow by haradabox (@haradabox) on CodePen.

問題ないですね。

Lv.2 凸形の要素(タブ風UI)

タブ選択で表示するコンテンツの切り替えができるUIを考えます。
選択しているタブと、コンテンツの周囲をシャドウで囲いたい、、、という欲求です。

ここからややこしくなってきます。

まず下記をご覧ください。

無邪気に

See the Pen Lv2.box-shadow--faild by haradabox (@haradabox) on CodePen.

タブ要素、コンテンツ要素共に周囲にシャドウを付けていますが、タブ要素にコンテンツ要素のシャドウが被ってしまっています。

これではいけませんね。

少し考えて

擬似要素とz-indexを利用し、被っているシャドウを消しました。

.box
  position: relative;
  z-index: 0;
  &__tab-item    
    &.--current
      position: relative;
      box-shadow: 0 1px 3px 0 #333;
      background-color: #fff;
      // コンテンツのシャドウを隠す
      &::after {
        position: absolute;
        bottom: 0;
        left: 0;
        height: 3px;
        width: 100%;
        content: "";
        background-color: #fff;
        z-index: 3;
      }
  &__body
    position: relative;
    z-index: 2;
    background-color: #fff;
    box-shadow: 0 1px 3px 0 #333;

See the Pen Lv2.box-shadow by haradabox (@haradabox) on CodePen.

よろしそうですね。

Lv.3 凹形の要素(チケット風UI)

お次は凹形の要素です。
チケットのような、切り欠きのある形を再現します。

惜しい

See the Pen Lv3.box-shadow--failed by haradabox (@haradabox) on CodePen.

丸い切り欠きの表現に、before擬似要素 + borderを使いました。
それっぽくはありますが、もうちょいいけそうですね?

それなりに

before擬似要素ではinsetのbox-shadowで円形のシャドウを作成します。
そして、背景色のbox-shadowを加えた、after擬似要素で、不要な箇所をマスクします。

See the Pen Lv3.box-shadow by haradabox (@haradabox) on CodePen.

よりそれっぽくなりました。

Lv.4 ギザギザ形の要素(アイコンと一体に)

Sass芸縛りプレイなので、rotateとskewを駆使して、、、という案は無視します。
となればSVGなんですが、、、

どうやってシャドウをつければいいのだっけ?

drop-shadowはボックスモデルに対して影がつくので、、、

See the Pen Lv4.box-shadow--svg-fail by haradabox (@haradabox) on CodePen.

まあこうなりますよね。

filterを使う

SVGには強い味方、filter: drop-shadowがあります。

表示したいSVGを前面に、シャドウ用のSVGを背面に配置し、シャドウで囲みたい部分(コンテンツなど)を挟み込みます。
また、filter: drop-shadowのプロパティはbox-shadowとは異なるため、数値は微調整します。

.box
  position: relative;
  z-index: 0; // シャドウが親要素の後ろに入り込まないように付与
  &__inner
    position: relative;
    border-radius: 8px;
    padding: 50px;
    background: #fff;
    box-shadow: 0 1px 3px 0 #333;
    z-index: auto; // 指定なしでもOKですが、回り込ませる対象としてわかりやすいかなーということで付与
  &__icon
    width: 100px;
    position: absolute;
    top: 0;
    left: 0;
    transform: translate(-30px, -30px);
    &.--shadow
      z-index: -1; // シャドウ用のSVG画像を.box__innerの後ろに回り込ませる
.svg-icon.--shadow
  filter: drop-shadow( 0 1px 1px #444); // filterでSVG画像に沿ったシャドウを付与

See the Pen Lv4.box-shadow--svg by haradabox (@haradabox) on CodePen.

私は満足です。

おまけ: ロングシャドウ

完璧ではないのですが、お蔵にするには勿体無いので、記載しておきます。

それがこちらです

.box
  position: relative;
  z-index: 0;
  &__inner
    position: relative;
    background: #fff;
    z-index: auto;
    &::before
      content: "";
      position: absolute;
      top: -1px;
      left: 0;
      width: 300px;
      height: 100%;
      transform: skew(0, 45deg);
      transform-origin: 0 0;
      background: linear-gradient(90deg, rgba(200,200,200,1) 0%, rgba(255,255,255,1) 100%);
      z-index: -1;
    &::after
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 300px;
      box-sizing: border-box;
      transform: skew(45deg);
      transform-origin: 0 0;
      background: linear-gradient(180deg, rgba(200,200,200,1) 0%, rgba(255,255,255,1) 100%);
      z-index: -1;

See the Pen extra.long-shadow by haradabox (@haradabox) on CodePen.

before擬似要素/after擬似要素でシャドウを作成します。
それぞれがシャドウを付与したい要素のheight/widthに依存し、skewで歪めることで汎用性のあるシャドウにしています。

グラデーションの角度調整(グラデーションの終端が要素の形になってしまう)が課題ですね。

まとめ

シャドウ効果はこんな感じで工夫が求められることが多いです。
しかしながら、裏を返せば工夫の発揮しどころ、実装を楽しめるポイントでもあります。

「他にもこんなシャドウ再現できまっせ」、ありましたら是非コメントをば!

gulpでコンパイルしたCSSの改行コードをLFからCRLFにする

$
0
0

はじめに

タスクランナー(gulp)でscssをコンパイルした所、cssの改行コードがLFに切り替わってしまうという事案が発生し、色々と検索をかけてもなかなかヒットしなかったので、今後同じようなことが起こった時用の備忘録です。(備忘録しか書いていない気がする)

インストールするnpm

gulp-load-plugins

gulp-からはじまるnpmパッケージを簡素化してくれます。
require()ばっかりにならなくて済みますね。
https://www.npmjs.com/package/gulp-load-plugins

gulp-line-ending-corrector

これは参考文献がなかなかに少ないのですが、改行コードを変更できるnpmパッケージという解釈です。
※いまいち良くわかってない
https://www.npmjs.com/package/gulp-line-ending-corrector

記述方法

const plugins = require('gulp-load-plugins')();

gulp-load-pluginsを読み込みます。

あとはgulpfile.jsのscss監視下のtask配下に

.pipe(plugins.lineEndingCorrector({
  verbose: false,
  eolc: 'CRLF'
}))

[HTML/CSS]CSSアニメーションだけでアコーディオンつくるぞ

$
0
0

inputlabelでアコーディオンつくった

inputlabelを使って、CSSだけでアコーディオンを作ったので備忘録として書くぞ。

See the Pen CSSでアコーディオン作る by mame_hashbill (@mayu-mameuda) on CodePen.

ちなみに領域外クリックでアコーディオン閉じるようにしたぞい。

これからCSSでアコーディオン作ろうとしてる人、なるべくコピペでなんとかなるようなシンプルな記述にしたので、べろっとコピって使ってもらえたら嬉しいぞい。

inputとlabelの関係性

(以前の記事に書いたやつとだいたい同じこと書く。
以前の記事→[HTML/CSS]チェックボックスの仕組みを使ってえだまめ無限プチプチをつくるぞ

さて、今回使うinputlabelは、よくお問い合わせフォームとかで
チェックボックスとかラジオボタンとかを作るときに使うやつだよな。

このinputlabelは、idforで関連づけることができて、
関連付けをするとlabelをクリックしても選択ができる(input部分にチェックがつけられる)ぞ。
こんな感じに。↓


See the Pen
rNamJmo
by mame_hashbill (@mayu-mameuda)
on CodePen.


<inputtype="checkbox"name="choice"id="choice-1"checked><labelfor="choice-1">選択肢1</label><inputtype="checkbox"name="choice"id="choice-2"><labelfor="choice-2">選択肢2</label><inputtype="checkbox"name="choice"id="choice-3"><labelfor="choice-3">選択肢3</label>

で、CSSでアコーディオンを作る上で重要なポイントは、
inputまたはlabelをクリックしたとき、checkedっていう状態が付与される点だな。

つまり、
checkedがついてる時はアコーディオンが開いていて、
ついてない時は閉じてる、っつう指定をしていくのだ。

HTML

使うHTMLはこんな感じ。

<body><inputtype="checkbox"name="accordion"id="accordion"><labelclass="overlay"for="accordion"></label><divclass="accordion"><labelclass="accordion__heading"for="accordion"><spanclass="accordion__icon"></span>title</label><divclass="accordion__item-wrap"><divclass="accordion__item">hogehoge</div><divclass="accordion__item">fugafuga</div><divclass="accordion__item">hogehoge</div><divclass="accordion__item">fugafuga</div></div></div></body>

inputが1つとlabelが2つ、上の方にいるな。

.overlay領域外クリックの時に使うlabel
.accordion__headingアコーディオン開閉に使うlabel

ほんで、inputはこの2つのlabelid="accordion"で結びついてるぞ。

titleクリックで矢印アイコンの向きを変える

矢印アイコンは、アコーディオンが開いた時にぐるっと上下が反転するようになってるよな。
この仕組みもアコーディオン開閉と仕組みは一緒なので、先にこっちを説明していく。

<inputtype="checkbox"name="accordion"id="accordion"><divclass="accordion"><labelclass="accordion__heading"for="accordion"><spanclass="accordion__icon"></span>title</label></div>

アイコンを動作させるのに必要なHTMLはこれだけ。
で、Scss。

$purple:#3B3955;%accordion,.accordion{&__heading{position:relative;}&__icon{&:before{//アコーディオンの矢印をCSSで作成content:" ";position:absolute;left:20px;top:16px;width:5px;height:5px;border:3pxsolid;border-color:transparent$purple$purpletransparent;transform:rotate(45deg);}}}input[name="accordion"]{display:none;//ラジオボタンを消す}#accordion:checked~{.accordion.accordion__icon{&:before{//check入ったときにアイコンを回転transform:rotate(-135deg);top:23px}}}

アイコン自体をCSSで作成してしまっている関係で:beforeの中にたくさん書いてあるのだけど、その辺の説明はこのサイトを参考にしたので、何してるか知りたい人は見てほしい。
【CSS】CSSのみで三角と矢印を作る方法

さてさて、
.accordion__iconでは、
とりあえず閉じている状態の下矢印アイコンを作成しているぞ。

で、そのあとの記述でinputdisplay:none;してるんだけど、
これは、今回はlabelクリックでcheckedが付与される仕組みを使いたいだけで、
input自体は画面に存在している必要がないため
だぞ。

チェック入ったときの指定方法

ほんで、inputを消したあとの記述で、labelをクリックしたとき(checked付与状態、つまりアコーディオン開いてる状態)の時のアイコンの指定をしているよ。
checked状態の指定は、checked ~に続けて書くのがお約束。

~は、間接セレクタっていうやつで、
兄弟関係にあれば間に別の要素が入っても指定ができる便利なセレクタだぞ。

【参考】間接セレクタ (E ~ F)


このセレクタの注意点としては、
~の後に指定するのは、必ず同階層にある要素にしないといけない決まりなので
アイコンをぐるっと回転させるには、
#accordion:checked ~ .accordion__iconという指定にせず、
#accordion:checked~ .accordion .accordion__icon
という指定にしないときかないんだなぁ。

ちなみにlabelinputの上にあったりしてもきかないので注意である。

アコーディオンを開閉させる

上と同じ仕組みを使って、いよいよアコーディオン開閉を作る。
HTMLは上に貼ったもの。

で、Scssはこんな感じ(アコーディオン開閉部分のみ抜き出してます)

%accordion,.accordion{&__heading,&__item{padding:020px040px;line-height:50px;letter-spacing:0.05em;}&__heading{background:white;color:$purple;font-weight:bold;position:relative;display:block;cursor:pointer;font-size:18px;}&__item-wrap{overflow:hidden;//これをやらないと中身が表示されちゃうので入れる}&__item{height:0;//閉じてるときは高さを0にしておくbackground:$purple;color:white;}}#accordion:checked~{.accordion.accordion__item{height:50px;transition:height.5s;}}

ポイントとしては2点で、
1. .accordion__item-wrapoverflow:hidden;して、はみ出た部分の表示(.accordion__item)を隠す。
2. .accordion__itemheight:0;にして、checkedが付与された時にheight:50px;にアニメーションさせる。

これでアコーディオンが開閉するようになるぞ。
この作り方だと、.accordion__itemにアニメーションの秒数指定をしているから、
項目がいくつ増えても指定した秒数で開閉できるのだ。

領域外クリックでアコーディオンを閉じる

最後に領域外クリックでアコーディオンを閉じる指定の仕方。

.overlayを領域いっぱいにかけてから、
pointer-events: none;で、ポインタの動作を全て無効化する。
この指定を入れることで、要素自体はあるけどクリックはできないようにできるぞ。

で、inputcheckedが付与されたあと、pointer-events: auto;でポインタの動作をデフォルトに戻して、.overlayを押せるようにするぞい。

<inputtype="checkbox"name="accordion"id="accordion"><labelclass="overlay"for="accordion"></label>
.overlay{pointer-events:none;//ポインタの動作全部無効化width:100%;height:100%;position:fixed;top:0;right:0;z-index:-1;}#accordion:checked~{.overlay{pointer-events:auto;//ポインタの動作デフォルトに戻す}}

こんな感じで、領域外をクリックしてもアコーディオンが閉じるようになる。

まとめ

アコーディオンが2つとか3つとかになると、領域外クリックで閉じるやつは無理なのかもしれない。。
その場合はやっぱりJSになっちゃうのかな〜〜〜〜〜〜〜・・・教えて詳しい人よ

スピードに特化したコーディング規約【QuiCSS】

$
0
0

QuiCSSとは

どのタグにクラスをつけるか、クラス名はどうするか、どこにスタイルを記述するか...
コーディングには迷う要素がたくさんあり、迷いこそが制作スピードのボトルネックになっています。

QuiCSS(クイックス)は、迷う時間を最小化高速でコーディングをするために設計された、BEMベースのコーディング規約です。

背景

FLOCSS、SMACSSなどいくつかのコーディング規約を試してみたのですが、規約が緩すぎて結局自分で考えなければならない箇所が多かったり、逆に構成が複雑すぎたり、小~中規模案件では必要が無いほどディレクトリが細分化されていたりして、どれもしっくりきませんでした。

QuiCSSはシンプルな構成かつ厳格なルールを採用し、少ない学習コストでコーディングスピードを上げることができるように設計されています。

必要な前提知識

・HTML、CSSの基本文法
・Sassの文法及びパーシャルによるファイル分割
・命名規則「BEM」の概要

メリット

・どのタグにクラスをつけるかが明確
・HTMLとCSSを行ったり来たりする必要がなくなる
・クラス名がすぐに決まる
・クラス名が重複する可能性がほとんど無い
・CSSをどのファイルに書くべきかが明確

デメリット

・使っている人が少ない
・HTML内の記述量が多くなりがち(Emmetを使っていてある程度のタイピングスピードがあれば、文字を入力する時間は迷う時間と比べるとずっと少ないので、記述量の増加はスピード的には問題になりません。)

内容

ディレクトリ構成

ディレクトリ構成
- index.html
- img/
- js/
- css/
- scss
  └── style.scss
  └── bases
      └── _reset.scss
      └── _config.scss
      └── _base.scss
      └── _mixin.scss
      └── _responsive.scss
      └── _utility.scss
  └── components
      └── _btn.scss
      └── _title.scss
      └── _form.scss
      └── _paging.scss
  └── layouts
      └── _header.scss
      └── _gnav.scss
      └── _main.scss
      └── _fnav.scss
      └── _footer.scss
  └── pages
      └── _idx.scss
      └── _abt.scss
      └── _ctt.scss
  └── pulgins
      └── _swiper.scss

basesディレクトリ
_reset.scss:ブラウザのデフォルトのスタイルをリセットするCSSを保存します。
_config.scss:カラーコード、ブレイクポイントなどを保存します。
_base.scss:タグに対して直接指定するスタイルを保存します。
_mixin.scss:メディアクエリなど、mixinを保存します。
_responsive.scss:レスポンシブ対応の際に使うクラスを保存します。(display: none;のつけ外しなど)
_utilities.scss:汎用クラスを使う場合には、このファイルに保存します。

その他、bootstrapなどのcssフレームワークの書き換えを行いたい場合には、適宜このディレクトリにファイルを追加してください。

componentsディレクトリ
ボタンやフォームなど、繰り返し使うパーツを1パーツ1ファイルで保存します。

作成したパーツを随時自分のテンプレートに追加して他の案件で流用することで、コーディングスピードをどんどんと上げていくことができます。

また他の案件でも(カスタマイズして)再利用できそうなパーツ以外は、無理に共通化せずにpagesディレクトリ内に繰り返し書いていくスタイルにした方が、結果として迷う時間が減ってコーディングスピードが上がります。

DRY(Don't Repeat Yourself)の原則は、ことCSSに関してはあまりストイックにならない方が良いと思っている派です。3、4回登場するくらいのスタイルの共通化で期待できる保守性の向上なんて、それによって必要になる思考量の増加と比べればたかが知れてます。

layoutsディレクトリ
ヘッダーやフッターなど、ほとんどのページで繰り返し使うエリアに関する記述を、1Block1ファイルで保存します。

pagesディレクトリ
各ページ固有のスタイルを1ページ1ファイルで保存します。
ファイル名は必ずアルファベット3文字にしてください。(後述するクラスの命名規則に関係します。)

pluginsディレクトリ
プラグイン固有のCSSがある場合、このディレクトリに保存します。

クラスの命名規則

クラスの命名はBEMがベースです。
Blockblock
Elementblock__element
Modifier-modifier
が基本形となります。。Modifierはマルチクラス方式を採用しました。

その他、詳細なルールを以下に記載します。

layoutsディレクトリに保存するスタイルのBlock名は固定
layoutsディレクトリに保存するBlockは、どの案件も大体同じものになります。
以下のようにBlock名を固定しましょう。
もし以下にないlayoutが必要になった場合には、その都度Block名を考えます。

layoutsディレクトリに保存するブロック名
<headerclass="header"><!-- ヘッダー --><navclass="gnav"><!-- グローバルナビ --><mainclass="main"><!-- メインコンテンツ --><footerclass="footer"><!-- フッター --><navclass="fnav"><!-- フッターナビ -->

pagesディレクトリ内のBlock名はファイル名の3文字 + その箇所を表す3文字
例えばindex.htmlに対するスタイルをscss/pages/_idx.scssに保存した場合、ブロック名はidxtopidxcttなどになります。
同じ名前のファイルを複数保存することはできないため、このルールによりクラス名が衝突する可能性はほぼ無くなります。
なお、ページごとにファイルを分割しているので、その箇所を表す3文字はある程度適当でOKです。(適当な名前でもどのスタイルを指しているかすぐに分かる)

element名はタグごとに固定する
divp以外のタグ
完全に1つに固定します。同じブロック内に複数の同一タグがあった場合には、modifierを使いましょう。

div,p以外のElement名
<h1h6class="block__ttl"><formclass="block__form"><tableclass="block__table"><ulclass="block__list"><olclass="block__list"><dlclass="block__def">

divp
用途が多すぎで1つに固定するのは難しいですが、以下のいずれかが使えるケースが多いです。
それっぽければなんでも良いのですが、よく使うものを固定化して、悩む時間を少なくすることが大切です。

div,pのElement名
<pclass="block__txt"><!-- テキスト系 --><pclass="block__ttl"><!-- タイトル系 --><pclass="block__btn"><!-- ボタン系 --><pclass="block__logo"><!-- ロゴ系 --><divclass="block__group"><!-- フォーム要素系 --><divclass="block__inner"><divclass="block__outer"><divclass="block__wrap"><divclass="block__box"><divclass="block__container">

クラスをつけるタグ、つけないタグ

クラスをつけるタグとつけないタグをあらかじめ決めておくことで、クラスをつけるかどうか迷う時間を無くします。またHTMLを一気に書き上げてからCSSを当てていくことができるようになるという意味でもスピードアップに貢献します。

クラスをつけるタグ
・大半のブロックレベルのタグ
header, footer, main, section, article, aside, nav, div, h1~h6, p, table, dl, ul, ol, ,iframe, form...

スタイルを当てる必要があるかどうかに関わらず、上記のタグには必ずクラスを指定します。

クラスをつけないタグ
・インラインレベルのタグ
a, span, img, em, strong, label, input, time...
・親要素が(ほぼ)決まっているタグ
li, thead, tbody, tr, th, td, dt, dd

上記のタグにはクラスをつけず、Sassのネストでスタイルを指定します。

Blockにするタグ、Elementにするタグ

BlockにするかElementにするかも、タグレベルで固定します。

Blockにするタグ
header, footer, main, article, section, aside

BlockにもElementにもなり得るタグ
div

Elementにするタグ
クラス付け対象の、その他全てのタグ
h1~6, p, ul, ol, dl, form, table, iframe...

componentsを利用する場合のクラスの付け方

上記のルールで付与した各クラスの前にcomponents用のクラスを追加します。

titleというcomponentsを使う場合
<divclass="idxtop"><h2class="title idxtop__ttl">ページタイトル</h2></div>

サンプル

サンプルをGitHubおよびGitHub Pagesに公開しました。
不明点等ございましたらお気軽にご質問ください。


Rails6でjqueryアニメーションライブラリanimsitionの使用 | 躓いたことなど...

$
0
0

1. rails6でanimsitionを使う

ビューにアニメーションを付けようと思い、試しにanimsitionというjqueryライブラリを使った.いくつか、躓いて勉強になったことをまとめる.

2. まずはダウンロード

ライブラリを下記のサイトからダウンロード(ZIP形式)
https://github.com/blivesta/animsition

3. webpacker経由だと動かない...

★解凍後、以下の2ファイルををapp/javascript/srcにコピー.
①dist/js/animsition.js
②dist/js/animsition.css
★app/javascript/packs/application.jsに追記

application.js
import"../src/animsition.js";import"../src/animsition.css";

★app/views/layouts/application.html.erbのheadタグ内に追記
➡jqueryを読み込む
➡application.jsを読み込む
これでビューでanimsition.jsとanimsition.cssを読み込めたはず...
readmeでanimsition.jsより先にjqueryを読み込むと書いてあったので、順番もいいはず...

application.html.erb
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

★ビューで動作確認のため、以下追記

show.html.erb
<div class="animsition">
  <a href="https://www.google.com/" class="animsition-link">animsition link 1</a> 
  <a href="https://www.google.com/" class="animsition-link">animsition link 2</a>
</div>
<script>
$(document).ready(function() {
  $(".animsition").animsition({
    inClass: 'rotate-in',
    outClass: 'rotate-out',
    inDuration: 1500,
    outDuration: 800,
    linkElement: '.animsition-link',
    // e.g. linkElement: 'a:not([target="_blank"]):not([href^="#"])'
    loading: true,
    loadingParentElement: 'body', //animsition wrapper element
    loadingClass: 'animsition-loading',
    loadingInner: '', // e.g '<img src="loading.svg" />'
    timeout: false,
    timeoutCountdown: 5000,
    onLoadEvent: true,
    browser: [ 'animation-duration', '-webkit-animation-duration'],
    // "browser" option allows you to disable the "animsition" in case the css property in the array is not supported by your browser.
    // The default setting is to disable the "animsition" in a browser that does not support "animation-duration".
    overlay : false,
    overlayClass : 'animsition-overlay-slide',
    overlayParentElement : 'body',
    transition: function(url){ window.location.href = url; }
  });
});
</script>

ページをリロードして確認...動かず...エラー出てる
animsition is not a functionみたいなよくあるエラー
animsition .jsファイルが読み込めてるか確認のため、jsファイルにalert文を仕込んだが、問題なく実行されていた.animsition .cssも一応確認したが、問題なし.

4. assets内にライブラリを配置して、読み込むと動いた!

webpacker経由で読み込むのはやめて、assets内からライブラリを読み込むようにしてみた.
★app/assets/の中にanimsition.jsとanimsition.cssをコピー
★application.html.erbに下記を追記
javascript_include_tag で個別に読み込んでみた.

application.html.erb
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<%= javascript_include_tag 'animsition.js' %>

★app/config/initializers/assets.rbに下記を追記
これを書かないとjavascript_include_tag が動かないらしい...

assets.rb
Rails.application.config.assets.precompile+=%w( animsition.js )

★ページをリロードして確認...動いた!

5. redirect_to以外の方法で遷移したページのアニメーションが動かない...

アニメーションが無事動いたが、問題が発覚.
redirect_toで遷移するページに記載したアニメーションは動作するが、redirect_toを使用しないで、遷移したページに記載したアニメーションは動作しないことがわかった.

6. data-turbolinkのせい!

どうやら、data-turbolinkの仕業でした.
data-turbolinkはheadタグを最初の1回しか読まずに、ページの表示を高速化するgemで、rails4からデフォルトで導入されている模様...
そして、data-turbolinkが働いて遷移したページではreadyイベントが発火しない事があるらしい.

★data-turbolinkをオフにする
遷移元のリンクタグにdata属性を追加

<%= link_to "マイページ", current_user, data: {"turbolinks" => false} %>

この設定を付けて、ページ遷移すれば、遷移先のアニメーションは無事動作した.

参考にしたページ
★Rails 4のturbolinksについて最低でも知っておきたい事
https://kray.jp/blog/must-know-about-turbolinks/
★Rails 5.0でlink_toでturbolinkを無効にする法
https://qiita.com/hodosan/items/ee84482d18d6dccd9488

【CSS】基礎

$
0
0

CSSとは

:sunny: HTMLを飾り付けしてくれる。(文字の色を変えてみたり、大きさを変えるなど)
:sunny: HTMLとは別のファイルに記述する。
:sunny:要素名に対してどういった飾り付けをするのかを指定していく
:sunny: HTMLでは要素名と呼ばれていたがCSSではセレクタと呼ばれる

:sunny:書き方の説明

セレクタ {
  プロパティ: 値;
}
書き方.css
h1{color:red;}

セレクタ・・・h1
プロパティ・・・color
値・・・red

セレクタにはHTMLの飾り付けしたい要素を入力。
→ h1を飾り付けてください!宣言
プロパティにはセレクタにどんな飾り付けを注文したいですか?
→ colorを指定するので h1 の文字の色を変えてください!
値にはプロパティの注文に対してどうしたいのかを答える
→ 文字の色は red でおねがいします!

NGな記入方法.css
h1{color:red;}

上記のような書き方はNGです:no_good:

もし h1 に飾り付けたい注文が文字の色と文字の大きさと・・・と複数の注文になってしまうと冗長になってしまいコードが見づらくなります。
なのでセレクタのあとの { で必ず改行すること。

あとは・・・
プロパティの前は字下げする。
プロパティの末尾に : を記入する。
値の末尾に ; を記入する。

color

:sunny:文字の色を変える
:sunny: 16進数のカラーコードで色を指定(#ff0000,#008000など)
:sunny:主要な色であれば直接色名を指定しても表示される(red,greenなど)

ちなみにカラーコードは原色大辞典がおすすめ:thumbsup:

例.html
<h1>16進数で指定した赤色の文字だよ</h1><p>直接redと色を指定した赤色の文字だよ</p>
例.css
h1{color:#ff0000;}p{color:red;}

Web

スクリーンショット 2019-12-24 18.58.22.png

どちらも赤色の文字が指定されました:laughing:

font-size

:sunny:文字の大きさを変える
:sunny:単位はピクセル(px)や%指定(ブラウザの文字基準の何%)などがある

例.html
<h1>文字の大きさを10pxにしてみました</h1><p>文字の大きさを20pxにしてみました</p>

CSSを指定しないと通常ではこのようにWebでは表示されます

スクリーンショット 2019-12-24 20.17.54.png

CSSで文字の大きさを指定すると・・・

例.css
h1{font-size:10px;}p{font-size:20px;}

Web

スクリーンショット 2019-12-24 20.22.11.png

文字の大きさが変わりました!:laughing:

font-family

:sunny:文字の種類を指定できる
:sunny: font-family: フォント名; と記入
:sunny:フォント名にスペースがある場合は、 " " で囲む

例.css
h1{font-family:serif;}p{font-family:"Avenir Next";}

Web

スクリーンショット 2019-12-24 20.36.34.png

background-color

:sunny:背景色を指定

例.css
h1{background-color:#ff0000;}p{background-color:#ffff00;}

Web

スクリーンショット 2019-12-24 20.42.31.png

width,height

:sunny: width は横幅を指定する
:sunny: height は高さを指定する
:sunny:単位はピクセル(px)や%指定(ブラウザの文字基準の何%)などがある

例.css
img{width:500px;height:100px;}

Web

スクリーンショット 2019-12-24 22.25.19.png

へちゃげたひよこちゃんになりました:sweat_smile:
ちなみに元のサイズはこちら

スクリーンショット 2019-12-24 22.34.17.png

class

例.html
<ul><li>りんご</li><li>いちご</li><li>メロン</li></ul>
例.css
li{color:red;}

上記のように設定するとWeb上では

スクリーンショット 2019-12-24 22.50.36.png

と表示される。
でもわかりやすいようにメロンだけ緑で表示したい。
この一部の要素にのみCSSで飾り付けたいときは class を使用する。

まずはHTMLを・・・

例.html
<ul><li>りんご</li><li>いちご</li><liclass="green-fruits">メロン</li></ul>

このように記入。
属性名を class とし、属性値を green-fruits とする(属性値に " " をつけ忘れないこと!)
class を使用すると属性値がクラス名になります。
クラス名は好きに決めれますが、わかりやすい名前をつけるほうがいいです。

例.css
li{color:red;}.green-fruits{color:green;}

Webを確認すると・・・

スクリーンショット 2019-12-24 23.02.24.png

メロンだけ緑になりました!

cssの書き方は

.クラス名 {
 プロパティ: 値;
}

となります。
冒頭に . をつけて続けてクラス名を記入したら後の書き方はセレクタのときと同じです。

忘年会のプレゼント交換で使用するWebサービスを作成した話

$
0
0

はじめに

この記事はOIC ITCreate Club Advent Calendar 2019の25日目の記事です。

きっかけ

弊部の忘年会の際にプレゼント交換をすることになったのですが、先輩から「なんか作れない?」という無茶振りを受け、作成しました。

実装

※忘年会前日に6時間で作成したものです。

完成したものはGitHub Pagesで公開しています。
こちらからアクセスできます。

早く作りたかったので使い慣れたNuxt.jsで開発しています。またBootstrapVueも使用しています。
詳しく知りたい方は、リポジトリを拝見下さい。

1 ... 人数を入力する画面

急遽キャンセルが出るとまずいので参加人数を入力できるようにします。
参加人数を入力後、スタートボタンを押すとstart()メソッドが呼び出されます。start()メソッド内では、入力された人数が0以下ならエラー文を表示します。また、data内で定義したstartedをtureにし、参加人数の入力画面からガチャを回す画面へと移ります。移る前に、gachaListへ人数分の長さを持つ配列を代入します。

pages/index.vue
<template><divclass="container p-5"><h1class="c-title text-center mb-5">ITC忘年会~プレゼント交換~</h1>

    // 1
    <formv-if="!started"@submit.prevent="start"><divclass="mb-5"><p>人数を入力してね!</p><divclass="d-flex align-items-end"><inputtype="number"class="form-control w-25 mr-3"v-model="peoples"/><div></div></div><pv-if="notPeoples"class="text-danger">1人以上入力してください。</p></div><divclass="text-center"><buttonclass="btn btn-primary px-5 py-2"@click="start">スタート</button></div></form></div></template><script>exportdefault{data(){return{peoples:1,notPeoples:false,gachaList:[],started:false}},methods:{start(){this.notPeoples=false;if(this.peoples<=0){this.notPeoples=true;return;}for(leti=1;i<=this.peoples;i++)this.gachaList.push(i);this.started=true;}}}</script><stylescoped>.c-title{font-size:64px;}</style>

2 ... ガチャを回す画面

スタートボタンが押された後に表示する画面です。
少し凝ったものを作成したかったため、CSSでガチャガチャを作成しました。また、回すボタンを押すとガチャガチャを回すアニメーションも作成しました。呼び出す側(親)からstartAnimationをガチャガチャコンポーネント(子)へ渡し、それがtrueの場合アニメーションが再生されるように実装しています。
ガチャガチャのCSSに関してはCodePenで公開しましたのでそちらをご確認下さい。

pages/index.vue
<template><divclass="container p-5"><h1class="c-title text-center mb-5">ITC忘年会~プレゼント交換~</h1>

    // 1
    <formv-if="!started"@submit.prevent="start">
      ...
    </form>

    // 2
    <divv-if="started"><div>残りカプセル:{{gachaList.length}}</div><Gacha:startAnimation="startAnimation"/><divclass="text-center"><buttontype="button"class="btn btn-primary px-5 py-2"@click="turn">回す</button></div></div></div></template><script>importGachafrom"~/components/Gacha"exportdefault{components:{Gacha},data(){return{...startAnimation:false}},methods:{...turn(){this.startAnimation=true;}}}</script>
...
components/Gacha.vue
<template><divclass="c-gacha"><divclass="c-gacha-container"><divclass="c-gacha-box"><divclass="c-gacha-capsule c-move-1"><divclass="c-gacha-capsule-color c-red"/></div><divclass="c-gacha-capsule c-move-2"><divclass="c-gacha-capsule-color c-blue"/></div>
        ...
      </div><divclass="c-gacha-body"><divclass="c-gacha-handle"><divv-if="startAnimation"class="c-gacha-handle-bar c-rotate-animation"/><divv-elseclass="c-gacha-handle-bar"/></div><divclass="c-gacha-exit"><divv-if="startAnimation"class="c-gacha-capsule c-show-animation"><divclass="c-gacha-capsule-color":style="{background: returnColor()}" />
          </div></div></div></div></div></template><script>exportdefault{props:{startAnimation:{default:false}},data(){return{colorClass:['red','blue','green','yellow']}},methods:{returnColor(){returnthis.colorClass[Math.floor(Math.random()*4)];}}}</script><stylescoped>...</style>

3 ... どのプレゼントが当たったかを表示するモーダル

ガチャを回した後にどのプレゼントが当たったかを表示するモーダルです。
※事前にプレゼントに番号を振っておきましょう

回すボタンを押すとランダムな値(0 〜 gachaListの長さ - 1の間)を生成します。それを使用しモーダルに表示する数字を決定します。
ガチャガチャのアニメーションが終了してからopenModal()メソッドを呼び出し、showModaltrueにすることでモーダルを表示しています。また、自分のプレゼントを引いてしまった場合を考慮し、モーダルにはカプセルを戻すボタンも付けました。
ガチャを続けるボタンを押すとsplice()メソッドを使用しgachaList[ランダムな値]を取り除きます。

pages/index.vue
<template><divclass="container p-5"><h1class="c-title text-center mb-5">ITC忘年会~プレゼント交換~</h1>

    // 1
    <formv-if="!started"@submit.prevent="start">
      ...
    </form>

    // 2
    <divv-if="started">
      ...
    </div>

    // 3
    <modalv-if="showModal":number="hitPeopleNumber"@returnCapsule="returnCapsule"@continueGacha="continueGacha"/></div></template><script>...importModalfrom"~/components/Modal"exportdefault{components:{...Modal},data(){return{...randomIndex:0,hitPeopleNumber:0,showModal:false}},methods:{...turn(){...this.randomIndex=Math.floor(Math.random()*this.gachaList.length);this.hitPeopleNumber=this.gachaList[this.randomIndex];setTimeout(this.openModal,4000);},openModal(){this.showModal=true;},returnCapsule(){this.startAnimation=false;this.showModal=false;},continueGacha(){this.gachaList.splice(this.randomIndex,1);this.startAnimation=false;this.showModal=false;}}}</script>
...
components/Modal.vue
<template><div><divclass="c-modal"><divclass="c-modal-content"><h3class="c-modal-title">{{number}}</h3><divclass="c-modal-footer"><buttonclass="btn btn-danger mb-3"@click="returnCapsule">カプセルを戻す</button><buttonclass="btn btn-primary mb-3"@click="continueGacha">ガチャを続ける</button></div></div></div></div></template><script>exportdefault{props:{number:{default:1}},methods:{close(){this.$emit('closeModal');},returnCapsule(){this.$emit('returnCapsule');},continueGacha(){this.$emit('continueGacha');}}}</script><stylescoped>.c-modal{width:100vw;height:100vh;background-color:rgba(100,100,100,0.4);position:fixed;top:0;left:0;}.c-modal-content{width:50%;height:500px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:white;text-align:center;}.c-modal-title{position:absolute;top:42.5%;left:50%;transform:translate(-50%,-50%);font-size:150px;}.c-modal-footer{display:flex;flex-wrap:wrap;position:absolute;width:100%;justify-content:space-around;bottom:30px;padding:020px;}</style>

4 ... 終了を表示するモーダル

ガチャガチャを回し終わった後に表示するモーダルです。
ガチャガチャを人数分回しgachaListの長さが0になると、finishedtrueとなり、終了を表示するモーダルが表示されます。モーダルの閉じるボタンを押すと参加人数を入力する画面へ切り替わります。

pages/index.vue
<template><divclass="container p-5"><h1class="c-title text-center mb-5">ITC忘年会~プレゼント交換~</h1>

    // 1
    <formv-if="!started"@submit.prevent="start">
      ...
    </form>

    // 2
    <divv-if="started">
      ...
    </div>

    // 3
    <modal.../>

    // 4
    <finish-modalv-if="finished"@close="closeFinishModal"/></div></template><script>...importFinishModalfrom"~/components/FinishModal"exportdefault{components:{...FinishModal},data(){return{...finished:false}},methods:{...continueGacha(){...if(this.gachaList.length===0)this.finish();},finish(){this.finished=true;},closeFinishModal(){this.started=false;this.finished=false;}}}</script>
...
components/FinishModal.vue
<template><div><divclass="c-modal"><divclass="c-modal-content"><h3class="c-modal-title">終了しました!</h3><buttonclass="btn btn-primary px-5 c-modal-btn-primary"@click="close">閉じる</button></div></div></div></template><script>exportdefault{methods:{close(){this.$emit('close');}}}</script><stylescoped>.c-modal{width:100vw;height:100vh;background-color:rgba(100,100,100,0.4);position:fixed;top:0;left:0;}.c-modal-content{width:50%;height:500px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:white;text-align:center;}.c-modal-title{width:100%;position:absolute;top:42.5%;left:50%;transform:translate(-50%,-50%);font-size:50px;padding:020px;}.c-modal-btn-primary{position:absolute;bottom:50px;left:50%;transform:translateX(-50%);}</style>

これで完成です。
再度ですが、こちらから完成したサービスを確認することができます。

最後に

実際の忘年会ではこのWebサービスを使用し、プレゼント交換が楽しく行われました。
参加して下さった方々が楽しそうにしていたので、作成した甲斐があったと思います。

font-familyについて本気で考えてみた

$
0
0

『CSS Advent Calendar 2019』最終日🎄。
担当は本日20代最後の日を迎える私です。
18日目(CSSの単位remの正しい使い方)も書いていますのでよろしくおねがいします。

今年はmacOSのアップデートによりヒラギノが動かなくなったり、
来年初頭にはWindows7がサポート終了、Edgeのブラウザエンジン変更など、
エンドユーザーの環境を考えなければならない節目の時です。

そこでいつもコピペで済ましているfont-familyについて1から考え直してみます。
全部読もうとしている人はスクロールバーを見てから考えてください。

結果

コピペユーザーのために先に結果を記載します。
ブログ等に転載する場合はこのページのURLぐらい貼ってください。

@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:100;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:200;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:300;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:400;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Bold");font-weight:bold;}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji";}

Github: RinoTsuka/jp-font-family

確認済み環境

IE11EdgeChromeFirefoxsafariアルファベット日本語
Windows7--Segoe UIOriginal Yu Gothic
Windows7(Noto)-Segoe UINoto Sans CJK JP
Windows8.1-Segoe UIYu Gothic
Windows8.1(Noto)-Segoe UINoto Sans CJK
Windows10-Segoe UIOriginal Yu Gothic
Windows10(Noto)-Segoe UINoto Sans CJK JP
macOS 10.12--San FranciscoHiragino Sans
macOS 10.13--San FranciscoHiragino Sans
macOS 10.14--San FranciscoHiragino Sans
macOS 10.15--San FranciscoHiragino Sans
Ubuntu 18.04以上---Noto Sans CJK JP?Noto Sans CJK JP
iOS 11未満----HelveticaNeueHiragino Kaku Gothic ProN
iOS 11以上----San FranciscoHiragino Sans
Android----RobotoNoto Sans CJK JP

動作確認いただけましたらコメントで教えてもらえると幸いです。

考えたいこと

なんとなく書いてるけど「なんでこのような書き方をするの?」を考えてみます。

対象環境

環境のサポート状況や需要を考えて、対象環境を決めてみます。

ブラウザ

対象ブラウザ

・Internet Explorer
・Edge
・Google Chrome
・Firefox
・safari
・safari(iOS)
・Chrome(And)
利用者数から対象ブラウザは上記とします。
さようならopera。(ブラウザエンジンはGoogle Chromeと同じなので大体Chromeと一緒です)

対象バージョン

基本的には最新から2つ前までのバージョンぐらいで良いかなと考えています。2つ前にもなると利用者が大幅に減るためです。
そんなにfont-familyの仕様は変わらないのでブラウザのバージョンに神経質になる必要はないと思います。
ただしIEは除く。
Windows7がサポート終了になりますが、あと数年はWindows7に対してサポートすることになるでしょう。
Windows7で使える最も古い物はIE8ですが、サポートが切れるWindows7のためにIE10以前をサポートするにはCSS開発コスパが悪すぎるので、対象はIE11にすることにします。

参考:各Windows OSで利用できるIEのバージョンを知る:Tech TIPS - @IT

OS

Windows

こちらはユーザー数ではなく、MicrosoftがサポートしているOSか否かで判断します。
Windows7のサポートが終了になり、Windows 8.1から游ゴシックが搭載されるのですが、莫大なユーザー数を抱えるWindows7を切るわけにはいかないので、1,2年は対象としなければならないでしょう。
なのでWindows7以上を対象とします。

mac

まず私のQiitaの記事のとある1ヶ月のmacユーザーです。(Windowsと比べて異常なmac率です)
ga.png

10.11のOSになるとかなり閲覧者が減ります。
10.12このラインを取りたいと思います。
これは『10.11 El Capitan』がOS X、『10.12 Sierra』がmacOSとなる分岐点でもあります。
macOSになるとHiragino Sansというフォントが登場することになります。
同時にSan Franciscoも登場しています。
これでmacで対象とするOSは全てHiragino Sansが使えることになります。

Linux

Linuxはコマンドラインからしか触らないのでよく知らないのですが、Ubuntu 18.04からNoto CJK(Noto Sans CJK JP)が標準らしいです。
sans-serifこれを記載するだけでNoto Sansが適用されるようです。
ユーザー数がほとんどいないので、OSバージョンではなくNoto Sansを採用することにします。

参考: Ubuntu 18.04 LTSの日本語フォントを変更する!【詳細解説】 | LFI

iOS(iPadOS)

ユーザー数が多く、日本語フォントの種類が少ないためすべて対応します。

Android

Noto Sans CJK JPを搭載の機種を対象とします。

htmlbodyはどちらに記述するべきか?

どちらでも問題ないようです。
font-sizeなどなどbodyに書くと思うので、見やすくするためにbodyに統一して書きたいですね。

CSS - Bootstrapはなぜhtmlとbody両方にfont-familyを記述しているのか?|teratail

どんなときにクォーテーションで囲うのか?

マルチバイトまたは半角スペースが含まれるときにクォーテーションで囲います。
囲う必要がない場合は囲わないほうが数バイトですが、容量の削減が出来ます。
またIEは必要ない場合に囲むと、適用されないものもあります。

// 囲うbody{font-family:"游ゴシック","Hiragino Sans","🇯🇵";}// 囲う必要がない(囲っても動く)body{font-family:-apple-system,HiraKakuProN-W3,sans-serif;}

'(シングルクォーテーション)と"(ダブルクォーテーション)どちらを使えばいいのか?

答えはどっちでも良いです。
どちらを使っても同じです。、コーディング規約があるならそちらに従いましょう。
なければどちらか好みの方に決めてしまいましょう。

// これは気持ち悪いbody{font-family:"Sample Win",'Sample Mac',sans-serif;}

『何か理由があって分けてるのか?』と誤解を招かれるかもしれないので統一しましょう。

絵文字について😘

絵文字について考えたことありますか?
私は全く気にしたことがなかったのですが、どうやらちゃんと指定しないと、IEでモノクロの絵文字が表示されるようです。
データベースはmb4で対応しているのにfont-familyは対応しないなんてありえない!
ということで絵文字用のフォントもfont-familyに記載していきます。

参考:絵文字😇を含むテキストを表示する @font-face 設定(Unicode 10.0対応版) | ダーシマ・ヱンヂニヤリング

日本語表記とアルファベット表記を併用する必要があるのか?

ないです!
昔々、日本語表記をしないと反映されないブラウザがあったそうな。
safariでは日本語表記を認識しなかったそうですが、現在は認識されているようです。
いつから認識するようになったかは不明。
また、日本語表記とアルファベット表記で違うものを読み込んでいる特殊なフォントもあります。
なので全てアルファベット表記で揃えましょう。

日本語とアルファベットでfontを変える必要があるのか?

body{font-family:Arial,Meiryo;}

などメイリオにもアルファベットが内包されいてるのになぜArialを記載するのでしょうか?
これはMeiryoのアルファベットがArialに比べてキレイではないから、という理由でこのような書き方をされてきました。
日本語はアルファベットに比べて文字がでかい。それに合わせてアルファベットの文字が作成されているので、総じて日本語フォントのアルファベットは純粋なアルファベットフォントと比べ、見た目で劣ります。
なので基本的にはこのような書き方をすることが必要です。
しかし、後述しますが例外フォントが存在するのです。

カーニングについて

カーニング(font-feature-settings)ですが、できるフォントとできないフォントが存在します。
カーニングできるフォントのみでfont-familyを構成することは出来ないので、考えないことにします。
font-feature-settingsを設定する場合、カーニング出来たらラッキー!ぐらいに考えてください。

候補に上がるフォント

気になりごとが調べ終わりました。
まずは一般的に利用されてきたフォント、新たに候補に加えるに値するフォントを列挙します。
いずれかの環境に入っていて、無償でダウンロードできるフォントを△とします。

WindowsmacOSLinuxiOSAndroid
アルファベット
Segoe UI
Verdana
Arial
-apple-system
BlinkMacSystemFont
Helvetica Neue
Helvetica
Roboto○ 
日本語
Yu Gothic
YuGothic
Meiryo
BIZ UDPGothic
UD Digi Kyokasho
MS PGothic
Hiragino Sans
Hiragino Kaku Gothic ProN
Osaka
Noto Sans CJK JP
Droid Sans
絵文字
Segoe UI Emoji
Segoe UI Symbol
Apple Color Emoji
Noto Sans Emoji
共通
sans-serif

こんな漢字でしょうか?
いくつか見慣れないものがあるかもしれませんが、後述します。

うんちく💩

ちょっと余談。

游ゴシックのフォント名

Windowとmacで微妙に違う。
※今回これが後でこれが重要なポイントになる。

WindowはYu Gothicで日本語表記は游ゴシック
macはYuGothicで日本語表記は游ゴシック体

-apple-systemとBlinkMacSystemFont

mac用のフォントだが、フォント名とは全然違うSan Franciscoというフォントが適用される。
参考:San Francisco フォントを探る - Qiita

BlinkMacSystemFontはレンダリングエンジンBlink搭載ブラウザ(Chrome, Opera)で適用される。
-apple-systemその他ブラウザで適用される。
GoogleとAppleの(ブラウザ)仲の悪さからこうなったのだろうか?

Hiragino Kaku Gothic ProNの『N』ってなによ?

hiragino.png

Hiragino Kaku Gothic ProNHiragino Kaku Gothic Proを比較して『N』はいくつかの漢字が旧字体になります。
Hiragino SansProN寄りです。

参考: ProとProN、StdとStdNの違い - フォント専門サイト fontnavi

Window10の新フォント

Window10はアップデートでいくつかのモリサワフォントが追加されています

UDデジタル教科書体(UD Digi Kyokasho NK-R)
その名の通り教科書向けに作成されたフォントです。
UDとはユニバーサルデザインのことで、見た目よりも読みやすさを優先したフォントにつけられることが多いです。

BIZ UDゴシック(BIZ UDPGothic, BIZ UDGothic)

Microsoft Officeに特化したフォントだそうです。
Officeに特化というだけあってWindows10以外でも利用できるようにMORISAWA BIZ+に登録するとダウンロードできるようになっています。BIZだけど個人でもOK!
ゴシック体だけではなくBIZ UD明朝という明朝体も同時に採用されています。

見た目は游ゴシックよりもメイリオより。
Windowsの日本語フォントの中ではダントツに可読性が高いです。
ただし仮想ボディーギリギリまで利用しているので、他のフォントと比較するとline-heightが小さく見えます。

フォントラインナップ | MORISAWA BIZ+ | フォント製品 | 製品/ソリューション | 株式会社モリサワ
ダウンロード:「MORISAWA BIZ+ 無償版」(旧:MORISAWA BIZ+「BIZ UD ゴシック/明朝 スタンダード版」)書体改訂のご案内[2018.10.24] – BIZ+

問題点のあるフォント

Yu Gothic

・IEで下部に余白ができるバグがある。
游ゴシックが一般的に使われているので今回は無視することにします。
気になるのであれば、IE11をハックなどでメイリオにすると良いです。
・Chromeでfont-weight: 400;のときかすれて見れる不具合がある。

Segoe UI

U+2546のグリフが、U+2545と同じになっているバグがある。
Segoe - Wikipedia

U+2546を利用することは無いと思うので見なかったことにしましょう。
あなたの環境で正しく表示されているか分かりませんがこんな文字です。 →

-apple-system, BlinkMacSystemFont, Hiragino Sans

ウエイトの種類が多いので、ウエイトの少ない日本語フォントと組み合わせたとき、日本語とアルファベットでウエイトに差が出てしまう。
Hiragino Sansと組み合わせることで回避出来ます。

Hiragino Kaku Gothic ProN

macOS CatalinaでHiragino Kaku Gothic ProNが適用されない。

よく調べていないので下記サイトを御覧ください。
Mac Catalina WEBでのヒラギノフォント表示問題について考えたメモ - かもメモ

BIZ UDPGothic

バグでは無いと思うが、英数字がやたらとデカイ。
アルファベットフォントが適用されていれば上記は関係なくなる。

font-familyを作る

ようやくfont-familyを書きます。

Original Yu Gothic

まず、Google Chromeの游ゴシックが細い問題に対処します。
詳細はfont-familyにChromeでも読みやすい游ゴシックを指定する方法 - Qiita

@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:100;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:200;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:300;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:400;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Bold");font-weight:bold;}body{font-family:"Original Yu Gothic";}

(以降@font-faceが行を占領するので省略します)

すべて並べる

アルファベット、日本語、共通、絵文字の順で、更にいい感じのフォント順に並べていきます。

body{font-family:-apple-system,BlinkMacSystemFont,"Helvetica Neue",Helvetica,"Segoe UI",Verdana,Arial,Roboto,"Hiragino Sans","Hiragino Kaku Gothic ProN",YuGothic,Osaka,"Noto Sans CJK JP","BIZ UDPGothic","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

こんな感じでしょうか。
ここから上から順に見ていきます。
問題がある場合を記載します。

Helvetica Neue, Helvetica

対象環境を決めています。macOSでは全て-apple-systemが搭載されているのでHelvetica Neue, Helveticaは不要なので削除します。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Verdana,Arial,Roboto,"Hiragino Sans","Hiragino Kaku Gothic ProN",YuGothic,Osaka,"Noto Sans CJK JP","BIZ UDPGothic","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

Verdana, Arial

対象のWindowsにはSegoe UIが搭載されているので不要です。
ArialはiOSでも採用されていますが、iOS11以前の環境でも-apple-systemが利用できる(San Franciscoではない)ためこちらも不要です。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Hiragino Kaku Gothic ProN",YuGothic,Osaka,"Noto Sans CJK JP","BIZ UDPGothic","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

これでアルファベットが-apple-system, BlinkMacSystemFont, Segoe UI, Robotoの4つに確定しました。

Hiragino Kaku Gothic ProN

古いiOSで必要ですがmacには不要です。
iOSではHiragino Kaku Gothic ProNが無くなればsans-serifが適用され結果的にHiragino Kaku Gothic ProNが適用されます。
なので削除します。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans",YuGothic,Osaka,"Noto Sans CJK JP","BIZ UDPGothic","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

YuGothic

mac用の游ゴシック。
Hiragino Sansがあるので不要です。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans",Osaka,"Noto Sans CJK JP","BIZ UDPGothic","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

Osaka

もうこの時代に記載する必要は無いですね。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","BIZ UDPGothic","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

BIZ UDPGothic

Windowsの新しいフォントの1つですね。
個人的にすごく読みやすいのですが、いかんせん文字がデカイ。
行間をBIZ UDPGothicに合わせると他のフォントの行間が想定より大きくなり、
他のフォントに合わせるとBIZ UDPGothicがギチギチになってしまう。
デザインの難易度が上がってしまうので、残念ながら外します。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","UD Digi Kyokasho","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

UD Digi Kyokasho

Windowsの新しいフォントのもう1つ。
『教科書』をうたうだけあり、ハネや強弱などしっかりしていて読み物には良さそうですが、小さい文字では潰れがちで向いてない感じがしました。
フォントとしては好きですがWebに向いていないのでこれは削除します。
あくまで一般的で無いだけで、電子書籍等のサイトでは採用してみるのも面白いかもしれません。

UDデジタル教科書体提供開始 | 株式会社モリサワ

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

Yu Gothic

最初にOriginal Yu Gothicを定義しているので不要です。
有ってもいいです。

以前ブラウザに翻弄されて、怖い経験があるのでフォールバックとして残します。
悪戦苦闘のあと → 2020年まで使えるfont-familyおすすめゴシック体 - Qiita

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic",Meiryo,"MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

Meiryo

長年親しんだフォントですが、もはや不要。
対象のWindowsでは sans-serif = Meiryo です。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic","MS PGothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

MS PGothic

もはや言うこともないぐらい不要。
今のデフォルトはメイリオなので適用されてしまったら劣化します。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic","Droid Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

Droid Sans

Droid Sans = sans-serifなので、こいつを消せば終わりです。

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji",;}

完成

これで完成です。
省略していた@font-faceを表示して、最後に整形してあげます。

@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:100;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:200;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:300;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Medium");font-weight:400;}@font-face{font-family:"Original Yu Gothic";src:local("Yu Gothic Bold");font-weight:bold;}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Hiragino Sans","Noto Sans CJK JP","Original Yu Gothic","Yu Gothic",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Sans Emoji";}

このfont-familyのメリットはmacでfont-weightが100〜900まですべて使えるという事です。
なのでこれからはfont-weightnormal, boldで記述していた人は数値で入力する癖をつけないといけませんね。

教えて

Bootstrapを参考にしたのですが、Segoe UI Emoji, Segoe UI Symbolと2種類記載する理由が分かりませでした。
ご存じの方いましたらご教授ください。

最後に

2020年まで使えるfont-familyおすすめゴシック体 - Qiitaでは多数の方にご迷惑をおかけしました。(私のせいでは無いけれど)
慣れ親しんだフォントが記載されなくなって、なんだか不思議な感じです。

斜め読みした方も、全部読んでくれた方もお疲れさまでした。
1ヶ月以上前から書き始めて、何度も何度も修正したので変なところがあるかもしれません。
見つけたらご指摘ください。

絵文字とスマホはもうちょっと改良の余地があるかもしれない。

要素の表示非表示は visibility:hidden の方が display:none よりも高速

$
0
0

はじめに

ACCESS Advent Calendar 2019 の25日目最終日です。

初めまして、今年一番ハマったソシャゲはドラクエウォークの @naohikowatanabeです。

HTML 的要素の表示非表示の基本

一般的には HTML 的に要素の表示非表示を行う際、以下のように言われます。
・要素の非表示は display:none か visibility:hidden で実現出来る
・visibility:hidden は「見えない+要素自体は存在する」
・display:none は「見えない+要素自体無し」
・visibility:hidden の方が要素の削除が無いので高速

本記事ではどの程度速度に差があるのか、を見ていきます。
#組込ブラウザのお仕事をやっているとお客さんからこの質問が非常に多い。。
#なのでまとめてしまう。

測定

display:none と visibility:hidden の違いの HTML をベースに、
「display:none による表示非表示100万回」
「visibility:hidden による表示非表示100万回」
を行うようにコードを変更し、測定します。

html

<!doctype html><htmllang="ja"><head><metacharset="UTF-8"><title>difference between visibility hidden and display none</title><linkrel="stylesheet"href="css/style.css"><script>constloop_count=1000000;functionvisibilityhidden(){consttwo=document.getElementById("two");conststartTime=Date.now();for(i=0;i<loop_count;i++){two.style.visibility="hidden";two.style.visibility="visible";}constendTime=Date.now();console.log("visibility:hidden "+(endTime-startTime)+" [msec]");}functiondisplaynone(){constthree=document.getElementById("three");conststartTime=Date.now();for(i=0;i<loop_count;i++){three.style.display="none";three.style.display="inline";}constendTime=Date.now();console.log("display:none "+(endTime-startTime)+" [msec]");}</script></head><body><divid="one"class="box"></div><divid="two"class="box"><h3>Visibility:hidden</h3>エレメント描画されず。けど、表示エリアは「残る」。背景色で塗りつぶした感じ。
    </div><divid="three"class="box"><h3>display:none</h3>エレメントが表示エリアから消える。DOMとして存在はするけど描画されない。
    </div><divid="four"class="box"></div><buttononclick="visibilityhidden()">visibility:hidden * 100万回</button><buttononclick="displaynone()">display:none * 100万回</button></body></html>

CSS

オリジナルから変えてません。

@charset"UTF-8";.box{width:150px;height:150px;margin:10px;border-radius:10px;/* CSS3草案 */-webkit-border-radius:10px;/* Safari,Google Chrome用 */-moz-border-radius:10px;/* Firefox用 */float:left;padding:20px;}#one{background:#000;}#two{/*visibility:hidden;*/background:#9eccb3;}#three{background:#f47d44;/*display:none;*/}#four{background:#000;clear:right;}

表示結果

Screenshot2019-11-26_1.png

測定結果

やり方時間[msec]
display:none 100万回888
visibility:hidden 100万回1000

display:none の方が1割程度高速です。
PC 環境ではあまり気にならないですが、
組込環境ではマシンパワーが非力な場合が多いのでこういうところで少しずつ気を付けるのが良いですね。

Screenshot2019-11-26.png

まとめ

要素の表示非表示は visibility:hidden の方が display:none よりも1割程度高速。

参考

display:none と visibility:hidden の違い

終わりに

本記事で ACCESS Advent Calendar 2019 無事終了です。
ここまで見ていただいた皆様に感謝です。

それでは皆様、良いお年を!
来年もよろしくお願いします!

Viewing all 8498 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>