AndroidでOSの文字サイズ設定を変更しても、ブラウザで文字の大きさが変わらない

Androidでは、設定にある「表示サイズとテキスト」を変更した場合、webサイトの文字サイズが可変します。
iOSにおけるDynamic Typeの有効化のための特殊な指定や、font-sizeをremにするといった対応は不要です。

OSの設定のほかに、ブラウザにも文字サイズの変更設定があり、OS全体ではなくブラウザのみ変更することも可能です。

しかし、一部環境ではこの文字サイズの可変が正しく動作しない場合があります。

## 可変しないケース1:文字数が少ない

AndroidのChromeで次のHTMLを表示したとき、文字サイズはOS/ブラウザの設定値に応じて可変になります。

※ 以降のサンプルで `word-break: break-all;` を指定していますが、これはサンプルテキストが画面幅を突き抜けるのを防ぐための指定で、文字サイズ可変の挙動とは無関係
```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
</style>
</head>
<body>
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
</body>
</html>
```
<img width="200px" alt="文字サイズ設定が反映される" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/6f48097c-3118-63c1-edb7-5b7e55434ae8.png">


表示するテキストを減らした場合、OS/ブラウザの設定値を無視し、CSSの設定のまま表示されます。

```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
</style>
</head>
<body>
123456789012345678901234567890
</body>
</html>
```
<img width="200px" alt="文字サイズ設定が反映されない" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/57c10607-06da-90bb-64cd-4e75c40b6f83.png">

コンテンツのテキスト量が少ない場合、文字サイズ可変が無効化されるようです。

## 可変しないケース2:font-sizeが小さい
テキスト量が同じでも`font-size`の指定値によって可変が有効/無効になる場合があります。  
次のサンプルのテキスト量では`font-size`が未設定の場合、可変が無効になります。

```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
</style>
</head>
<body>
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
</body>
</html>
```

<img width="200px" alt="文字サイズ設定が反映されない" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/4b1ff71a-e140-80c2-76da-0d4c02a3bccf.png">

しかし、デフォルトの16pxよりも大きいfont-sizeを指定すると、テキスト量が同じでも可変が有効になります。
```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
body{
  font-size:17px;
}
</style>
</head>
<body>
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
</body>
</html>
```

<img width="200px" alt="文字サイズ設定が反映さる" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/af3eee86-ec62-9973-1d84-ac3d07e1ac7a.png">

## 可変しないケース3:画面幅が広い
テキスト量、`font-size`が同じでも、画面幅によって可変が有効/無効になる場合があります。 

以下のサンプルは、ポートレートモードで表示している場合、可変が有効になります。

```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
</style>
</head>
<body>
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
</body>
</html>
```
<img width="200px" alt="文字サイズ設定が反映される" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/fecb97af-1883-97d1-bc42-4e11a19973d5.png">

しかしランドスケープモードでは可変が無効になります

<img width="356px" alt="文字サイズ設定が反映されない" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/8c64b0fc-2d0c-5ee4-6bc8-17977386a837.png">


## 可変しないケース4:特定のスタイルが指定されている

要素に特定のスタイルがあたっていると、文字サイズ可変が無効になる場合があります。

```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
p{height:100%;}
</style>
</head>
<body>
<p>123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
</body>
</html>
```

<img width="200px" alt="文字サイズ設定が反映されない" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/bf70d05d-0661-d28c-1090-cedb3cf36717.png">

## 何が起きているか

可変になる文字数を確認すると、

* `font-size:10px`のときは165文字
* `font-size:20px`のときは83文字

`font-size`が倍のとき文字数は半減しています。  

ざっくりとしたイメージとして、テキストの文字数*`font-size`で求められる、「テキストが専有している領域」のようなものがしきい値として利用されていると考えられます。

また、ランドスケープ時の場合を確認すると

* `font-size:10px`のときは317文字
* `font-size:20px`のときは159文字

このときの画面幅の比率は、
`792 / 412.190 = 1.92144399427`  
（ポートレートが`412.190px`、ランドスケープが`792px`）

それぞれの文字数の比率は  
`317 / 165 = 1.92121212121`  
`159 / 83 = 1.9156626506`  

ということで、近似した結果が得られました。
可変になる条件としての「テキストが専有している領域」の大きさは、画面幅応じて変化するようです。

文字数ではどうしても細かい数値でブレが出るため、100文字と1000文字で可変になる`font-size`をそれぞれ確認してみました。
（`font-size`は小数点以下のかなり細かい数字まで判定しているため、小数点以下12桁程度を目処に確認しています）

* ポートレートで100文字のときは `16.479998588562...px` 
* ポートレートで1000文字のときは `1.64799994230...px` 
* ランドスケープで100文字のときは `31.679999351502...px` 
* ランドスケープで1000文字のときは `3.168px` 

「テキストが専有している領域」に換算すると
* ポートレートが `1647.999...`
* ランドスケープが `3167.999...` - `3168`

それぞれの画面幅で割ってみると

* ポートレートは `1648 / 412.19 = 3.99815619011`
* ランドスケープは `3168 / 792 = 4`

となり、「テキストが専有している領域」が `画面幅 * 4` を上回ったとき、テキストの可変が有効になることがわかりました。


### 除外される要素
可変しないケース4のように、特定のスタイルが指定されている場合その要素の中のテキストは文字サイズの可変から除外されます。無効になるスタイルは以下を確認しています。（他にも存在する可能性があります）

* `height` (値の単位は何でも)
* `position: absolute;`
* `position: fixed;`
* `white-space: nowrap;`
* `white-space: pre`


このうち、`height`、`position`については、`body`より下の要素に設定した場合のみ無効になります。

つまり、
```
html,body{
  height:100%;
}
```
このような`html`,`body`に対する`height`指定では、文字サイズ可変は有効なままですが、


```
html,body{
  height:100%;
}
body > div{
  height:100%;
}
```
このように`body`直下に`div`を置き、それに`height:100%;`を指定すると、その`div`は子孫要素を含めて文字サイズ可変が無効になります。


#### 除外される要素の挙動
除外されるスタイルが指定された要素のなかのテキストについては、以下の挙動をしています。
* 文字サイズ可変が有効の場合でも、文字サイズは可変しない
* 文字サイズ可変が有効になるテキスト量のカウントから除外される

##### 文字サイズ可変が有効の場合でも、文字サイズは可変しない
次のサンプルでは
 * `div` はスタイル指定なし
 * `p` は `height:100%;`
 
という指定のため、`div`の子孫にあるテキストのみ可変になります。

```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
p{height:100%;}
</style>
</head>
<body>
<div>123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</div>

<p>123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
</body>
</html>
```

<img width="200px" alt="Screenshot_20220928-113823.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/b2b042cb-eb6e-9e22-e6f5-68c251bc7ead.png">


##### 可変が有効になるテキスト量のカウントから除外される
除外されるスタイルが指定された要素の中にあるテキストは、可変が有効になるためのテキスト量のカウントに含まれないようです。

次のサンプルでは
* `div` のテキスト量が少ない
* `p` のテキスト量は可変になるテキスト量として十分だが、`height`が指定されている

という条件のため、`div`の子孫にあるテキストは可変になりません。


```
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<style>
body{word-break: break-all;}
p{height:100%;}
</style>
</head>
<body>
<div>1234567890</div>

<p>123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
</body>
</html>
```

<img width="200px" alt="Screenshot_20220928-113844.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5323/b2ee1685-208d-ccbd-559f-144fee3c47f6.png">


## 対応したコード

「テキストが専有している領域」が `画面幅 * 4` を上回ったとき、テキストの可変が有効になることがわかりました。

これは逆に言うと、`font-size:400vw`なテキストが1文字でもコンテンツに存在すれば、テキストの可変が有効になることになります。

また、以下のテキストが「テキストが専有している領域」の対象になることも確認しました。
* HTMLではなくCSSの`content`プロパティによって生成された文字
* 半角スペース

よって、次のように`content`プロパティによって`400vw`の半角スペースを追加しておくことで、コンテンツの文字量、サイズ、画面幅に関係なく、テキストの可変を有効にすることができます。

```
html::after{
  content: "\00a0";
  display: block;
  width:1px;
  font-size:400vw;
  margin-top:-5rem;
  line-height:1;
  pointer-events: none;
  overflow: hidden;
}

```