CSS の Cascade Layers を触ってみた

Chromium Blog: Chrome 99: CSS Cascade Layers, a New Picker for Input Elements, and More

CSSCascade Layers が Google Chrome 99 で実装されるという事なので勉強してみます

まずは仕様確認

6.4. Cascade Layers - CSS Cascading and Inheritance Level 5

(layer)というとペイント系ツールの表示の(layer)とか CSS なら z-index とかのコンテンツ表示の(layer)を連想しますが 6.2. Cascading Origins - CSS Cascading and Inheritance Level 5 に新たな(layer)の加える話らしいです

試しに書いてみるとこんな感じ

<title>CSS @Layer test</title>
<style>
@layer base, value, override;

p {
  color:black;
  background-color: white;
}

@layer value {
  :root {
    --green: green;
    --blue: blue;
  }
}

@layer override {
  p {color: var(--green);}
  p.a {color: var(--green);}
  .b {color: var(--green);}
  .c {color: var(--green);}
  .d {color: var(--green);}
}

@layer base {
  p {color: var(--blue);}
  p.a {color: var(--blue);}
  .b {color: var(--blue);}
  p > span.c {color: var(--blue);}
  .d {color: var(--blue) !important;}
}
</style>
<p>Black text.</p>
<p class="a">Black text.</p>
<p><span class="b">Green text.</span></p>
<p><span class="c">Green text.</span></p>
<p><span class="d">Blue text.</span></p>

まず @layer の外の記述が @layer 内の記述より優先されます

CSS Selectorによる優先順位より @layer の概念の方が上なので、@layer の外の p への指定が @layer の内の p.a より優先されます

CSSでは先に記述された内容を後に記述した内容が上書きする仕組みになっていますが @layer を使うと名前単位でグループ化でき、 @layer の名前だけを先に記述することでもこの上書き順序を制御できます

@layer base;
@layer value;
@layer override;

この場合 @layer base@layer value、それを更に @layer override; が上書きする事になります

これを @layer base, value, override; とカンマ区切りで 1 にまとめることもできます

上記の例では @layer basep > span.c {color: green;} より @layer override.c {color: green;} の方が強くなっています

更に @layer より !important 方が優先されるので @layer としては下位でも @layer base の中の !important 付きの記述の方が他の @layer の中の !important がない記述より優先されます

あくまで上書きの優先順位なので、ある @layer から別 @layer のカスタムプロパティーを参照することは @layer による上位、下位に関係なくできます (同じカスタムプロパティーがあれば上書きは発生しますが)

更に @import で外部CSSを読み込む際に layer(...) として @import 先に丸ごと @layer の名前を設定することができます

この時 @import 先の CSS の中で @layer が使われていれば @layer は階層構造作るので @import 元/先で @layer の名前が重複しても意図しない上書きを避ける事ができます

@layer base;
@import url(default.css) layer(default);
@layer override {
    /* ... */
}
@import url(theme.css) layer(theme);

@layer base {
    /* ... */
}

@layer default {
    @layer base {/* ... */}
    @layer override {/* ... */}
}

@layer theme.override {
    /* ... */
}

とりあえずさっと調べた所ではこんな感じで CSS@layer 単位でまとめておくことで記述を追加したりリファクタリングの際に予期せぬ上書きを防ぐことができそうです

ISOWeek を使って ISO の週番号を計算する

ある日の ISO 8601 の週番号を知りたいことがあります

先週とか今週HTMLtime 要素でマークアップする時です

の日記で今週マークアップする時は、2020年の33週目なので <time datetime="2020-W33">今週</time> になります

HTML2.4.5.8 WeeksISO 8601 の週番号は異なる場合がありますが For modern purposes, a week as defined here is equivalent to ISO weeks as defined in ISO 8601. [ISO8601] とある通り普段はあまり気にする必要がないので今回は無視します

ついでに言うと ISO 8601 では月曜日を週の初めとしているので、例えば日曜日始まりで2020年11月第1週を表現したい場合は 2020年11月1日から7日 などの表現に変えた方が妥当かもしれません


この ISO 8601 の週番号の計算は .NETISOWeek クラス (System.Globalization) | Microsoft Docs で簡単に行う事が出来ます

PowerShellISOWeekGetWeekOfYear を使って今日の週番号を計算するコードは以下の通りです

ps> [Globalization.ISOWeek]::GetWeekOfYear([Datetime]::Now);
33

非常に個人的な話で恐縮ですが、私は ISO 8601 の週番号を計算する関数を自作する前に知りたかったです

HTML5のidはエンコードして使おう

HTML5の話題としては周回遅れの話題だと思いますが、私は最近HTML5のidはHTML4.01の頃の制約がなくなっていたのでちゃんとエスケープやエンコードをしないと危ないと知ったという話です

現在のHTMLのid属性の値

When specified on HTML elements, the id attribute value must be unique amongst all the IDs in the element's tree and must contain at least one character. The value must not contain any ASCII whitespace.

文書内で一意で、1文字以上で、ASCII空白を含んで居なければよい

ASCII空白はU+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE.のこと

HTML4.01のid属性の値

ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

HTML4.01のid (とname) 属性の値は、英字 (A-Za-z) の何れかから始まり、続いて任意の数の英字 (A-Za-z)、数字 (0-9)、ハイフン (-)、アンダースコア (-)、コロン(:)、ピリオド(.) で構成されている必要がありました

具体的な影響

現在のHTMLのid属性の値は、HTML4.01のid属性の値を包括していますので既存のidを変更したり、今後新たなidを作る場合も運用を変える必要はありません

一方、HTML4.01の頃のまま、例えばidからリンク付きの目次を作成する処理やCSSセレクターの作成する支援する処理などがある場合は注意が必要です

例えば以下のHTML断片はHTML5では仕様に準拠しています

<p id="###">###</p>
<p id="abc?query=efg">abc?query=efg</p>
<p id="a>b{color:red;}">a>b{color:red;}</p>

2019年の抱負の進捗状況 (6月3日時点)

この記事は自分向けの記事です

ニャオス

全体的に崩壊しているので、になったら半年経過と言う事で色々再度予定を立て直したいと思っています

もうちょっと頻繁にblogを更新する

一応緩く更新が続いていますので、このまま緩く更新を続けます

体重58kgまで落とし、維持する

やっとリバウンドが収まりつつあり、65kgを維持できてはいるのですが、減ってもいません

HTML LS Developer's Editionを一通り読む

先月は6月頭あたりに何らかの出力を始められれば、と思っていましたが、今の所何か出力に至る所まで行っていません

ざっくり1か月押し位の感じです

情報処理安全確保支援士を受験する

とりあえず秋に向けて勉強をしましょう (していない人の台詞)

江戸時代の元号をレジストリィに足したが.NETのJapaneseCalendar Classの下限値は西暦1868年9月8日だったので和暦変換できなかった話

タイトルが全ての出落ち記事です

何がやりたかったのか

令和のレジストリィがWindows Updateで提供されたりされなかったり、一緒に文字幅が変わる修正が提供されてGUIがぶっ壊れたりしている今日この頃、皆様いかがお過ごしでしょうか

自分は思い付きでトラブルを増やすべく、江戸時代の元号Windows 10のレジストリィに追加してどうなるか試してみることにしました

レジストリィの場所とデータの形式

元号の情報を持っているレジストリィは HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras にあります

内容をPowerShellで取得するとこんな感じです

PS > Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras';

    Hive: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese

Name                           Property
----                           --------
Eras                           1868 01 01 : 明治_明_Meiji_M
                               1912 07 30 : 大正_大_Taisho_T
                               1926 12 25 : 昭和_昭_Showa_S
                               1989 01 08 : 平成_平_Heisei_H
                               2019 05 01 : 令和_令_Reiwa_R

このレジストリィの仕様は見当たらなかったのですが、直感的に値の名前を開始年月日を yyyy MM dd の形で持ち、値は元号の漢字表記、漢字表記の1文字目、ヘボン式ローマ字表記、ヘボン式ローマ字表記1文字目を _ を区切り子として持っているようです

江戸時代まで遡って元号レジストリィに登録してみる

元号一覧 (日本) - Wikipedia を参考に江戸時代までのCSVを用意して取り込んでみることにします

[String] $registryKeyPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras';
[String] $csvPath = '.\JapanseEraInEdo.csv';

Get-Content -Path $csvPath |
ConvertFrom-CSV |
Where-Object {
    $null -ne ($_.StartDate -as [DateTime])
} |
ForEach-Object {
    Add-Member -InputObject $_ -MemberType NoteProperty -Name 'Name' -Value ($_.StartDate -as [DateTime]).ToString('yyyy MM dd');
    Add-Member -InputObject $_ -MemberType NoteProperty -Name 'Value' -Value (($_.KanjiEraName, $_.KanjiEraName[0], $_.RomanAlphabetEraName, $_.RomanAlphabetEraName[0]) -join '_');
    Write-Output $_;
} |
Where-Object {
    $_.Name -notin (Get-Member -InputObject (Get-ItemProperty -Path $registryKeyPath) | ForEach-Object {$_.Name})
} |
New-ItemProperty -Path $registryKeyPath > $null;
PS > Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras';

    Hive: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese


Name                           Property
----                           --------
Eras                           1868 01 01 : 明治_明_Meiji_M
                               1912 07 30 : 大正_大_Taisho_T
                               1926 12 25 : 昭和_昭_Showa_S
                               1989 01 08 : 平成_平_Heisei_H
                               2019 05 01 : 令和_令_Reiwa_R
                               1615 09 05 : 元和_元_Genna_G
                               1624 04 17 : 寛永_寛_Kan'ei_K
                               1645 01 13 : 正保_正_Shouhou_S
                               1648 04 07 : 慶安_慶_Keian_K
                               1652 10 20 : 承応_承_Jouou_J
                               1655 05 18 : 明暦_明_Meireki_M
                               1658 08 21 : 万治_万_Manji_M
                               1661 05 23 : 寛文_寛_Kanbun_K
                               1673 10 30 : 延宝_延_Enpou_E
                               1681 11 09 : 天和_天_Tenna_T
                               1684 04 05 : 貞享_貞_Joukyou_J
                               1688 10 23 : 元禄_元_Genroku_G
                               1704 04 16 : 宝永_宝_Houei_H
                               1711 06 11 : 正徳_正_Shoutoku_S
                               1716 08 09 : 享保_享_Kyouhou_K
                               1736 06 07 : 元文_元_Genbun_G
                               1741 04 12 : 寛保_寛_Kanpou_K
                               1744 04 03 : 延享_延_Enkyou_E
                               1748 08 05 : 寛延_寛_Kan'en_K
                               1751 12 14 : 宝暦_宝_Houreki_H
                               1764 06 30 : 明和_明_Meiwa_M
                               1772 12 10 : 安永_安_An’ei_A
                               1781 04 25 : 天明_天_Tenmei_T
                               1789 02 19 : 寛政_寛_Kansei_K
                               1801 03 19 : 享和_享_Kyouwa_K
                               1804 03 22 : 文化_文_Bunka_B
                               1818 05 26 : 文政_文_Bunsei_B
                               1831 01 23 : 天保_天_Tenpou_T
                               1845 01 09 : 弘化_弘_Kouka_K
                               1848 04 01 : 嘉永_嘉_Kaei_K
                               1855 01 15 : 安政_安_Ansei_A
                               1860 04 08 : 万延_万_Man'en_M
                               1861 03 29 : 文久_文_Bunkyuu_B
                               1864 03 27 : 元治_元_Genji_G
                               1865 05 01 : 慶応_慶_Keiou_K

JapaneseCalendar classを使って江戸時代の日付を元号表示 (しようと) する (がエラーになる)

PS > [CultureInfo] $culture = [CultureInfo]::New("ja-JP");
PS > [Globalization.JapaneseCalendar] $culture.DateTimeFormat.Calendar = [System.Globalization.JapaneseCalendar]::new();
PS > ([Datetime]'1865/05/01').ToString('ggy年', $culture);

"2" 個の引数を指定して "ToString" を呼び出し中に例外が発生しました: "指定された引数は、有効な値の範囲内にありません。
パラメーター名:時間値が年号の範囲を超えています。"
発生場所 行:3 文字:1
+ ([Datetime]'1865/05/01').ToString('ggy年', $culture);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentOutOfRangeException

エラーになりました

指定された引数は、有効な値の範囲内にありません。パラメーター名:時間値が年号の範囲を超えています。 とのことなのでこの期に及んでJapaneseCalendar Classの仕様を調べます

JapaneseCalendar Class (System.Globalization) | Microsoft Docs

This class handles dates from September 8 in the year Meiji 1 (in the Gregorian calendar, September 8, 1868). Although the Japanese calendar was switched from a lunar calendar to a solar calendar in the year Meiji 6 (1873 of the Gregorian calendar), this implementation is based on the solar calendar only.

どっとはらい

2019年の抱負の進捗状況 (5月7日時点)

この記事は自分向けの記事です

もうちょっと頻繁にblogを更新する

robert.kimata.infoドメインのweblogとの使い分けを考えつつも、一応先月は1本記事を掛けたので、まあいいかくらいの感覚です

blogの更新を目標とはしていますが、義務として更新を始めると途端にやる気がなくなりますし、知ったかぶりをして間違った記事を書き始めたりしますので、書くことがなかった月は正しく書くことがなかったとして処理しております

体重58kgまで落とし、維持する

やっとリバウンドが収まりつつあり、現時点で先月と同等の65kgを維持出来ました

とは言えには61.65kgだった体重が3.3kg程増えていますので、再び体重を減らすところから始めないといけません

経験上、一度減量していると暫くの間は体がそれに慣れていてリバウンドが始まってから同じ方法で減量してもなかなか体重が減らなくなると知っているので何か新しい手を考えないといけません

HTML LS Developer's Editionを一通り読む

5月の連休が明けたので予定通りそろそろ読み始めるつもりです

来月頭あたりに何らかの出力を始められればと思っています

情報処理安全確保支援士を受験する

また秋に頑張りましょう

……今から

しかし、合格したい試験は情報処理安全確保支援士なのですが、現在の私の知識や業務内容と合っていないのでのでそれなりに勉強せねばならず (合格したいならすれば良いだけなのですが) そこがなかなか苦痛です

どうしたものか

<s>未解決: </s>Android版Google Chromeは本文が245文字以上か未満かで文字サイズが変わる、そして245文字以上の場合で`position: absolute;`のstyleを持つ文字サイズは小さくなる

本記事は不具合の再現手順を説明するだけで解決方法の説明はありません

meta要素のviewportを設定することで問題が解消することが分かりました

以下、憶測ですが、スマートフォンなどの小さい画面で表示し、meta要素のviewportがない場合、内部的にviewport相当の設定され、かつ、その時特定の設定 (position: absolute;のstyle) を持つ文字にはその設定が有効になっていないため、文字サイズが変化するものと思われます

要点を箇条書きに

記事名の通りですが、我ながら何を言っているか大変分かりにくいので箇条書きにしてみます

  1. 以下をAndroidGoogle Chromeで確認した
  2. Desktop版Google ChromeでもデベロッパーモードにしてAndroidのモードにすると確認できる
  3. 本文 (Body要素内のtext node)が合計245文字以上か未満かで文字サイズが変わる
  4. この244文字/245文字の境界は、ASCII文字でもマルチバイト文字でも変わらない
  5. 245文字以上の場合で position: absolute; のstyleを持つ文字は小さくなる

やっぱりわかりにくいです

Test Case

244 Characters in body and position absolute contents text.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>244 Characters in body and position absolute contents text.</title>
    <style>
    p::before {
      position: absolute;
      content: 'ABCDEFGHIJ ';
    }
    </style>
  </head>
  <body>
    <p title='Char 001-100'>1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
    <p title='Char 101-200'>1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
    <p title='Char 201-244'>12345678901234567890123456789012345678901234</p>
  </body>
</html>

245 Characters in body and position absolute contents text.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>245 Characters in body and position absolute contents text.</title>
    <style>
    p::before {
      position: absolute;
      content: 'ABCDEFGHIJ ';
    }
    </style>
  </head>
  <body>
    <p title='Char 001-100'>1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
    <p title='Char 101-200'>1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890</p>
    <p title='Char 201-245'>123456789012345678901234567890123456789012345</p>
  </body>
</html>

これをDesktop版Google Chrome検証 (I)で表示してAndroid版として描画すると以下の様になります

f:id:rh-kimata:20190411212510p:plain

ちなみに、本文がASCII互換以外の文字、例えば漢字で 一二三四五六七八九〇... となっている場合も245文字以上か未満かで同じ現象が起こります

そもそも何でこんなことを調べたのか

元は別サイトで p 要素を li 要素みたいにカウンターを付けたくてそういうCSSを書いて AndroidGoogle Chromeで表示してみたら content: counter(paragraph) ". "; として生成したカウンターが読めないほど小さく表示され、色々調査した結果行きつきました

とりあえず、Google Chromeのバグっぽいので良かった、俺のせいじゃないと言う事で今回は良しとします (良くない)