#3 2020年10月にツイートしたHTML/CSS/JavaScriptのTipsまとめ
2020 年 10 月にツイートした HTML/CSS/JavaScript のツイートまとめです。見出しをクリックするとツイート元に遷移するので、気に入ったらフォロー・ファボ・リツイートお願いします。
download属性
1.a
要素に download
属性をつけると、href
属性で指定した URL のファイルをダウンロードさせられます。
<a href="path/to/file.zip" download>ダウンロード</a>
ただし、href
属性に指定した URL が Web サイトと同一ドメインである必要があり、別ドメインの場合は通常のリンクと同じように遷移します。
SVGのフォーカス
2.button
や a
要素内に svg
要素があるとき、IE ではタブキーによる移動で 2 度フォーカスが当たったり、スクリーンリーダーに 2 回読み上げられたりします。
<button>
<svg focusable="false">...</svg>
</button>
<a href="#">
<svg focusable="false">...</svg>
</a>
svg
要素に focusable
属性を指定しておくと、この問題を解決できます。
見出しタグと<br>
3.見出しの装飾目的で <br>
タグを使ってしまうとスクリーンリーダーに読み上げられる際、その前後で途切れた読まれ方になってしまいます。下記の例では、「Hello (一呼吸) World!」と読み上げられます。
<h2>Hello<br>World!</h2>
そこで、

を使って改行文字を入れて、white-space: pre-line;
の指定でそのまま改行が反映されるようにします。こうすることで、「Hello World!」と自然な読み上げ方になります。
<h2>Hello 
 World!</h2>
h2 {
white-space: pre-line;
}


でなくとも、ユニコードやアスキーコードで改行させることもできますが、この方が直感的でわかりやすいと思います。また、スマホだけ改行したいというような場合があると思います。
<h2>Hello 
 World!</h2>
@media (max-width: 414px) {
h2 {
white-space: pre-line;
}
}
そのときはメディアクエリを使って、特定の画面幅のときだけ pre-line
値にすれば良いです。
:any-link疑似クラス
4.:any-link
は :link
または :visited
に一致するすべてのリンク要素にマッチします。
nav :any-link { ... }
// これと同じ
nav :link, nav :visited { ... }
対応していないブラウザには、postcss-pseudo-class-any-link を使えば :link
と :visited
に変換してくれます。
:focus-visible疑似クラス
5.:focus-visible
を使うとキーボードでフォーカスされたときを判定できます。:focus { outline: 0}
としてしまうと、キーボードで移動したときにどこにフォーカスが当たっているのかわからないのでダメですが、:focus-visible
を使うことでキーボード以外のときだけフォーカスリングを消せるようになります。
:focus {
// フォーカスされたとき
}
:focus-visible {
// キーボードを使ってフォーカスされたとき
}
:focus:not(:focus-visible) {
// キーボード以外(マウスやタッチなど)でフォーカスされたとき
// フォーカスリングを消す
outline: 0;
}
まだまだ対応しているブラウザは少ないため、what-input を使って対応すると良いです。
[data-whatinput="mouse"] :focus,
[data-whatinput="touch"] :focus {
// キーボード以外(マウスやタッチなど)でフォーカスされたとき
// フォーカスリングを消す
outline: 0;
}
@supportsとselector()関数
6.@supports
で selector()
関数を使うと、セレクタのサポート状況を判定でき、下記の場合は :is
セレクタの判定をしています。
@supports selector(:is(.a, .b)) {
// :isセレクタに対応しているとき
.selector {
property: value;
}
}
@supports not selector(:is(.a, .b)) {
// :isセレクタに対応していないとき
.selector {
property: value;
}
}
対応していないブラウザもあるため、別の構文を使ってセレクタの判定を行うこともできます。
_:is(.a, .b), .selector {
// :isセレクタに対応しているとき
property: value;
}
CSS のセレクタがパースされるとき、そのブラウザで実装されていないセレクタが使われていると、カンマで区切られた後の .selector
のスタイルは無視されます。
未満のメディアクエリ
7.780px
未満とするときに 1px
引いた (max-width: 779px)
とするのは良くないです。
// NG
@media (max-width: 779px) {
// 780px未満?
}
// OK
@media not all and (min-width: 780px) {
// 780px未満
}
not
演算子を使ってクエリを反転させてやれば良いです。理由など詳細については拙著『今すぐ使えるCSSレシピブック』に詳しく書いてあります。
CSS変数のアニメーション
8.@property
で定義された CSS 変数を transition
プロパティで使ってアニメーションさせるテクニックです。
<div></div>
@property --num {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
div {
transition: --num 5s;
counter-set: num var(--num);
font: 800 40px system-ui;
}
div::after {
content: counter(num);
}
div:hover {
--num: 100;
}
line-height: 1;
9.Chrome では input
要素に line-height: 1;
を指定しても無視され、normal
値と同じになってしまうので注意が必要です。
<input type="text" value="Text">
<input type="text" value="Text">
input:nth-child(1) {
line-height: 1;
}
input:nth-child(2) {
line-height: 1.02;
}
試しに 1.02
を指定してみると、無視されずに描画されていることがわかります。
オーバーレイテキスト
10.背景画像の上に黒の半透明レイヤーをのせたデザインを実装するテクニックです。
<div class="overlay-text">オーバーレイなテキスト</div>
.overlay-text {
padding: 6em 1em;
color: #fff;
text-align: center;
font-size: 1.2em;
background-image: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, .5)),
url('https://picsum.photos/1280/720');
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
background-image
プロパティでは先に記述した方が前面レイヤーとして描画されます。この場合は、黒の半透明レイヤーを linear-gradient()
で表現しています。
疑似要素を使ってもいいのですが、他の表現で疑似要素を使う場合があるのであえて linear-gradient()
を使っています。
縁取り文字
11.Web サイトに縁取り文字を入れるなら画像よりもインライン SVG を使うと変更に強いので便利です。
<svg viewBox="0 0 200 100">
<text
x="50%"
y="50%"
text-anchor="middle"
dominant-baseline="central"
fill="#fff"
stroke="#1699cb"
stroke-width="7"
stroke-linejoin="round"
stroke-linecap="round"
font-weight="bold"
paint-order="stroke"
>てきすと</text>
</svg>
通常 fill
→ stroke
の順に描画されるため、線を太くすると文字に被ってしまいますが、paint-order="stroke"
によって stroke
を背面に描画させられます。
<svg viewBox="0 0 200 100">
<use
xlink:href="#text"
fill="none"
stroke="#1699cb"
stroke-width="7"
stroke-linejoin="round"
stroke-linecap="round"/>
<text
id="text"
x="50%"
y="50%"
text-anchor="middle"
dominant-baseline="central"
fill="#fff"
font-weight="bold"
>てきすと</text>
</svg>
paint-order
に対応していない IE などでも実装したい場合は、use
要素を使ってテキスト部分を複製すれば良いです。
Masonryレイアウト
12.CSS Grid Layout Module Level 3 で CSS Grid を使った Masonry レイアウトを実装できる仕様がまとまったようです。
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<ol>
ol {
display: inline-grid;
grid: masonry / repeat(3, 2ch);
border: 1px solid;
masonry-auto-flow: next;
}
li {
background: silver;
}
li:nth-child(2n+1) {
background: pink;
height: 4em;
}
CSSオンリーな油絵の肖像画
13.CSSだけで肖像画を作っているすごい人がいます。他の作品もあるので GitHub を見てみると面白いかもしれません。
美しいtransformの作例
14.立体的なtransformの作例がたくさん見られます。
配列の空値とカンマ
15.JavaScript でデータテーブル構造などを配列で実装するとき、特に指定する値がない場合は空値(カンマだけ)をよく使います。
const array = [, , , , 1, 2]
console.log(array.length) // => 6
ただし、末尾のカンマは要素数に影響がないため注意してください。
const array = [, , , , 1, 2,]
console.log(array.length) // => 6
連番の配列
16.引数に最初と最後の値を指定すると、連番の配列を生成してくれる関数です。
const generateArray = (start, end) => [...Array(end + 1).keys()].slice(start)
console.log(generateArray(1, 5))
// => [1, 2, 3, 4, 5]
値の交換
17.2 つの変数の値を交換するときは分割代入を使うと楽です。
let a = 1
let b = 2
[a, b] = [b, a]
// => a = 2
// => b = 1
桁の区切り文字
18.数値の桁の区切りに _
(Numeric Separators)が使えます。
const number = 1_234_567
// => 1,234,567
requestAnimationFrame()とフレームレート
19.requestAnimationFrame()
は必ずしも 60fps 出るとは限らないので注意が必要です。iOS の低電力モードが ON になっているときは fps が落ちてかなりかくついて見えます。
また、クロスドメイン iframe 内で requestAnimationFrame()
を使ったときも、iOS ではフレームレートが落ちます。下記のサンプルを iOS Safari で見てみてください。
上が 60fps のアニメーションで下が意図的に 30fps にしたアニメーションです。iOS Safari だと 60fps ではなく、もっさりして見えると思います。しかし、iframe 内を一度タップすると 60fps で描画されるようになります。
requestAnimationFrame()
は animejs などほとんどのアニメーションライブラリで使われています。あくまでリクエストするだけで 60fps を保証するものではないので注意してください。
iOSの100vhバグ
20.iOS の 100vh バグを解決する記事を見て、少し負荷軽減してみました。
<div class="hero"></div>
.hero {
min-height: 100vh;
min-height: calc(var(--vh, 1vh) * 100);
}
let vw = window.innerWidth
// vhを設定する関数
const setViewportHeight = () => {
if (vw === window.innerWidth) {
// 画面の向きが変わらないときは無視
// アドレスバーの開閉でscrollイベントが発生するため
return
}
const vh = window.innerHeight * .01
document.documentElement.style.setProperty('--vh', `${vh}px`)
vw = window.innerWidth
}
// resizeイベント負荷軽減
const resizeEnd = (fn, time = 30) => {
let timeout
return (...args) => {
clearTimeout(timeout)
timeout = setTimeout(() => fn.apply(this, args), time)
}
}
// 画面サイズが変わったとき
window.addEventListener('resize', resizeEnd(setViewportHeight))
// ページ初回読み込み時
setViewportHeight()
requestAnimationFrame()
を使ってもいいかもしれないです。
dragmove.js
21.dragmove.js は超軽量なドラッグ&ドロップを実装できるライブラリです。
detect-gpu
22.detect-gpu は UserAgent の GPU 版のようなライブラリです。
SheetJS
23.SheetJS は Node.js で Excel ファイルの編集や更新ができるライブラリです。
data-picker
24.date-picker はアクセシブルな日付選択 UI ライブラリです。
importabular
25.importabular は簡易 spreadsheet を実装できるライブラリです。
Print.js
26.Print.js は PDF ファイルを新規タブで開くことなく、その Web サイト内で PDF の印刷画面を表示できるライブラリです。
ZzFXM
27.ZzFXM は音符と楽器データのパターンからステレオミュージックトラックを生成できるライブラリです。
Layoutit!
28.Layoutit! は直感的な操作で CSS Grid を生成できるオンラインジェネレーターです。
Blob generator
29.Blob generator はいい感じの Blob を生成してくれるオンラインジェネレーターです。
Discussion