PerlのText::Markdown::Discountで囲い付きコードブロックを扱う2022年12月11日 01時31分

この記事はPerl Advent Calendar 2022の11日目の分です。


PerlのText::Markdown::Discountモジュールを使うと、MarkdownをHTMLに変換できます。

use feature qw(say);
use Encode qw(encode_utf8);
use Text::Markdown::Discount qw(markdown);

say encode_utf8 markdown(<<'MARKDOWN');
こんにちは、世界。

* 順序
* なし
* リスト
MARKDOWN
<p>こんにちは、世界。</p>

<ul>
<li>順序</li>
<li>なし</li>
<li>リスト</li>
</ul>

オリジナルのMarkdownにはありませんが、CommonMarkおよびその拡張であるGitHub Flavored Markdownなどには囲い付きコードブロック(fenced code block)が存在します。3つ以上のバッククォート(`)の並びまたはチルダ(~)の並びで囲んだ部分が、HTMLのpre要素とcode要素を使って出力されるというものです。

Text::Markdown::Discountモジュール(の内部で使われているDiscountというMarkdown処理系)でも囲い付きコードブロックに対応していますが、扱い方がバージョンによって異なります。

Text::Markdown::Discount 0.14以降

囲い付きコードブロックを有効にするには、markdown関数の第2引数にMKD_FENCEDCODEフラグ(0x02000000)を指定します。

my $html = markdown(<<'MARKDOWN', Text::Markdown::Discount::MKD_NOHEADER | Text::Markdown::Discount::MKD_NOPANTS | 0x02000000);
```
fenced code block
```
MARKDOWN
<pre><code>fenced code block
</code></pre>

MKD_FENCEDCODEフラグはDiscount処理系で定義されているものの、Text::Markdown::Discountモジュールでは定数が定義されていていないため、フラグの値である0x02000000を直接指定しています。(定数を定義するpull requestが提出されています。)

MKD_NOHEADERフラグおよびMKD_NOPANTSフラグはmarkdown関数の第2引数を省略したときにデフォルトで適用されるフラグなので、元の挙動を変えずに別のフラグを追加する際には、このふたつのフラグも明示的に指定する必要があります。

MKD_FENCEDCODEフラグを指定しない場合、3つ以上のバッククォートの並びはインラインのコード範囲として解釈されます。

my $html = markdown(<<'MARKDOWN');
```
fenced code block
```
MARKDOWN
<p><code>
fenced code block
</code></p>

Text::Markdown::Discount 0.13

特にフラグを指定しなくても、囲い付きコードブロックが有効になっています。

my $html = markdown(<<'MARKDOWN');
```
fenced code block
```
MARKDOWN
<pre><code>fenced code block
</code></pre>

Text::Markdown::Discount 0.12以前

囲い付きコードブロックに対応していません。3つ以上のバッククォートの並びはインラインのコード範囲として解釈されます。

CSSの絶対配置の要素の静的位置矩形2022年12月11日 12時52分

この記事はCSS Advent Calendar 2022の11日目の分です。


CSSでpositoin: absolute(絶対配置)の要素の位置を指定するときには、topleftrightbottomプロパティ(またはこれらを一括指定するinsetプロパティ)がよく使われます。もし絶対配置の要素にそれらのプロパティが指定されていなかったら、その要素の位置はどこになるでしょうか?

その場合、絶対配置の要素は原則として「その要素がpositoin: static(静的配置)だった場合の位置(静的位置矩形; static-position rectangle)」に置かれます。絶対配置の要素の親要素がインライン要素だった場合、絶対配置の要素自身がdisplay: inline(インライン要素)かdisplay: block(ブロック要素)かによって位置が異なってくることになります(インライン要素の子要素が絶対配置のときのデモ)。

この挙動をうまく利用すれば、絶対配置の要素の親要素にposition: relativeをつけて回らなくても、絶対配置の要素を期待する位置に置けることがあります。その場合、細かな位置の調整にinsetプロパティなどを使うことはできないので、transform: translate(...)marginプロパティを使うことになります。

フレックスアイテムが絶対配置のとき

「原則として」というからには例外もあります。絶対配置のフレックスアイテムでinsetプロパティなどが指定されていないものは、フレックスコンテナの位置に置かれます。

(「フレックスコンテナ」はdisplay: flexまたはdisplay: inline-flexが指定された要素、「フレックスアイテム」はフレックスコンテナの子要素です。)

グリッドアイテムが絶対配置のとき

グリッドアイテムが絶対配置のときはちょっと複雑です。グリッドコンテナが静的配置なら、絶対配置のグリッドアイテムでinsetプロパティなどが指定されていないものは、グリッドコンテナの位置に置かれます。

グリッドコンテナが静的配置でないなら、絶対配置のグリッドアイテムでinsetプロパティが指定されていないものは、gridプロパティなどで指定されたグリッド領域の位置に置かれます(グリッドアイテムが絶対配置のときのデモ)。

(「グリッドコンテナ」はdisplay: gridまたはdisplay: inline-gridが指定された要素、「グリッドアイテム」はグリッドコンテナの子要素です。)

とはいえ、フレックスボックスやグリッドと絶対配置を組み合わせるとCSSのコードがだいぶ複雑になるので、普段は避けたほうがよいと思います。