透過 CSS 達到可折疊的 tree view

Hacker News 上看到「Tree views in css」這篇,講怎麼用純 CSS 技巧達到可折疊的 tree view:

主要是用了 ulli 的 html 結構來搭建 tree view 的意義,再透過 <summary><details> 這兩個本身就有 toggle 能力的元素來操作展開與收合,後面就是 visual effects 的設計了。

Can I use 這邊可以看到支援度沒什麼問題 (連 Android 4.4 的 WebView 都支援),除非你還得跟 IE11 奮戰:「Details & Summary elements」。

CSS 的 :has() 有新進展了

在「Using :has() as a CSS Parent Selector and much more」這邊看到 Safari 宣佈對 :has() 的支援,查了一下 Can I use... 上面的資料「:has() CSS relational pseudo-class」,看起來是從 15.4 (2022/05/14) 支援的。

隔壁 Google Chrome 將在下一個版本 105 (目前 stable channel 是 104) 支援 :has(),沒意外的話 Microsoft Edge 應該也會跟上去,看起來只剩下 Firefox 要開了。

先前在「Chromium 的 :has() 實做進展」這邊有翻一下進度,看起來 Chromium 這邊要進入收尾階段了。

等普及後一些延伸套件裡的寫法也可以用 :has() 來處理了,就不用自己在 javascript 裡面檢查半天...

透過一些簡單的設定,產生 RSS 頁面的 RSS Please (rsspls)

RSS Please 是一套簡單設定 (但應該是對 programmer 簡單),可以把網頁內容轉成 RSS/Atom feed 的軟體。

我把官網上範例的註解拿掉,可以看到你需要去讀 HTML 頁面的結構,然後找出對應的 css selector:

output = "/tmp"

[[feed]]
title = "My Great RSS Feed"
filename = "wezm.rss"

[feed.config]
url = "https://www.wezm.net/"
item = "article"
heading = "h3 a"
summary = ".post-body"
date = "time"

跟我在 feedgen 上用 Python 做的事情其實差不多,他用了彈性換方便性:rsspls 可以簡單設定一些值就生出一個 feed,而我這邊的 feedgen 需要寫一段 code (雖然不長);但因為 feedgen 是用 Python 處理事情,所以可以不只可以讀 HTML 也可以讀 JSON API,另外也可以設計一些轉換邏輯 (像是 summary 的部份)。

但有人寫起來推廣總是不錯...

DigitalOcean 買下 CSS-Tricks

Hacker News 首頁上看到的消息,DigitalOcean 買下 CSS-Tricks:「CSS-Tricks is joining DigitalOcean!」,DigitalOcean 的公告在「CSS-Tricks joins DigitalOcean, expanding our commitment to community」,而 Hacker News 上對應的討論在「DigitalOcean acquires CSS-tricks (css-tricks.com)」。

不知道 DigitalOcean 的想法,有人猜算是買媒體的一種,也有人猜是因為 css-tricks.com 的 SEO 分數超高。

對 css-tricks.com 這邊來說,基本上就是脫手賣掉?不過沒看到金額...

CSS4 的 aspect-ratio

Hacker News Daily 上看到 aspect-ratio 這個新的 CSS property 的介紹:「Aspect Ratio is Great」,對應的 Hacker News 討論則是在這:「Aspect-ratio is great (css-irl.info)」。

MDN 上的解釋是這樣:

The aspect-ratio CSS property sets a preferred aspect ratio for the box, which will be used in the calculation of auto sizes and some other layout functions.

對於圖片來說,這可以用來指定希望 crop 多少的範圍。

作者也有提到以往的 hack 方式是透過 paddingcalc + var 的方式達到,現在讓瀏覽器直接處理就簡單不少了,這張示意圖就蠻清楚表達想要做的事情是怎麼樣:

然後看了一下 Can I use 上面的資料,看起來許多大宗的瀏覽器都支援了,也包括了 Firefox 的 ESR 版本 (91,在 2021 年八月的時候釋出的);不過仔細看會發現 Safari 這邊寫 15 才支援,這代表 Catalina (10.15) 與 Big Sur (11) 的 Safari 都不支援,而這兩個版本目前 Apple 都還有支援,另外在行動裝置上,這也代表 iOS 的要求是 15+,所以目前還在支援的 iPhone 5SiPhone 6 用的 iOS 12 也會遇到問題:

不愧是新世代的 IE,對於需要服務比較一般性的情況應該還是不能用...

語意化的 CSS 設定 (Contextual awareness) 減少 side effect

前幾天在 Hacker News 上看到 CSS-Tricks 上的文章「You want enabling CSS selectors, not disabling ones」這篇,在講 CSS 的設計問題,對應的 Hacker News 討論在「You want enabling CSS selectors, not disabling ones (css-tricks.com)」這邊。

文章裡面引用文章裡面提到的文章也都蠻值得看的:「You want enabling CSS selectors, not disabling ones (2021/03/08)」、「Axiomatic CSS and Lobotomized Owls (2014/10/21)」。

其中 2014 年那篇居然是 A List Apart 上的文章,好久沒看到了這個站了... 也發現居然不在 RSS/Atom feed 清單裡面,重新訂起來。

這邊拿 A List Apart 上面的圖來說明,出自「CONTEXTUAL AWARENESS」這個段落的例子。

在很多段落時,我們常使用 margin-top (或是 margin-bottom,例子可以自己變換) 來設定間距,也就是 (a) 的例子。但可以看到第一個元素就會「多出來」:

A List Apart 裡面提到的解法是 * + * (或是 p + p,看你怎麼選 CSS selector),也就是前面有相鄰的元素才需要設定 margin-top

回到 CSS-Tracks 上的文章,有些人會這樣指定 CSS (這邊用 margin-bottom,所以搭搭配的是 :last-child):

.card {
  margin-bottom: 1rem;
}

/* Wait but not on the last one!! */
.parent-of-cards :last-child {
  margin-bottom: 0;
}

也就是全部都先加上 margin-bottom,然後針對最後一個元素拿掉 margin-bottom。而另外的版本則是:

.card:not(:last-child) {
  margin-bottom: 1rem;
}

或是:

/* Only space them out if they stack */
.card + .card {
  margin-top: 1rem;
}

這樣就不用蓋來蓋去,可以降低 side effect:margin-bottom 可能會在其他地方指定,你設為 0 可能是不對的值;另外寫成兩組時 CSS 的優先順序其實是不同的,Mozilla 的 Specificity 可以參考,Specifishity 這個網站給了很有趣的 cheatsheet (你要先了解才能當 cheatsheet 用):

在文章最後面有提到 gap 這個用法,查了一下「CSS property: gap: Supported in Grid Layout」,看起來現代的瀏覽器應該是都支援了,不過如果要支援舊的瀏覽器的話就是問題...

另外順便提一下,早期大家會偏好用 + 是因為 IE7+,而 :last-child 則是 IE9+ 了:「CSS Selectors and Pseudo Selectors and browser support」。雖然現在看起都是時代的眼淚了,但可以了解一下 2014 年的時候為什麼會偏好 + 的設計。

用 CSS Selector 產生 RSS feed

Hacker News 首頁看到「Show HN: RSS feeds for arbitrary websites using CSS selectors (vincenttunru.com)」這個,程式在 GitLab.com 上的「Feed me up, Scotty!」這邊,另外這個專案名稱是在玩 Star Trek 的梗:「Beam me up, Scotty」,然後這邊講的 RSS feed 已經算是通稱了,實際上大家都是輸出 Atom

他用的設定檔格式是 TOML,文章給的範例:

[funfacts]
title = "Wikipedia — did you know?"
url = "https://en.wikipedia.org/wiki/Main_Page"
entrySelector = "#mp-dyk > ul li"
titleSelector = "b"
linkSelector = "b a"

[wikivoyage]
title = "Wikivoyage recommendations"
url = "https://en.wikivoyage.org/wiki/Main_Page"
entrySelector = ".jcarousel-wrapper .jcarousel-item"
titleSelector = "h2"
linkSelector = "h2 a"

feed-me-up-scotty/src/index.ts 這邊看起來是 TypeScript 專案,然後用 browser 帶起 Firefox 來,可以預期會吃不少資源...

另外 Hacker News 的討論裡有另外提到「Feed Creator」,看起來也是個不錯的專案,有免費版與付費版...

Visual regression testing

看了「Catching CSS Regressions and Visual Bugs in Continuous Integration」這篇,原來這個叫做 visual regression testing,可以拿來檢查視覺上的差異:

出自「Visual Regression Testing Tools」。

這種 pixel-by-pixel 的測試也可以包在 CI 裡面,至少記錄起來可以在之後查。

看起來有不少 open source 工具與付費的服務可以用,不過機器的記憶體都會需要大一點 (需要瀏覽器的 rendering engine)。

Chromium 的 :has() 實做進展

前陣子在「Chromiu 看起來正在實做 CSS4 的 :has()」這邊提到了 Chromium:has() 實做,對應的票在「Issue 669058: CSS selectors Level 4: support :has()」這邊,不過看起來當時沒有實做完整,而且有測出問題:

The following css/selectors  web tests are failing on below platform:

css/selectors/has-basic.html - Failing on chrome/edge/firefox/safari/webkit
css/selectors/parsing/parse-has.html - Failing on chrome/edge/firefox/safari/webkit

昨天又看到新進度了:「Supports all ':has' relative argument cases」。

Supports all ':has' relative argument cases

Currently the relative selector is not supported yet, so this CL
provides the relative argument cases as follows.
 - :has(:scope > <complex-selector>)
 - :has(:scope ~ <complex-selector>)
 - :has(:scope + <complex-selector>)

看起來補上了之前沒實做的部份。更完整的討論過程可以參考 Gerrit 的「Supports all ':has' relative argument cases」這邊。

沒問題的話應該就是時間的問題了,也許三個月到半年左右?

Chromium 看起來正在實做 CSS4 的 :has()

先前一直都有在盯著「Issue 669058: CSS selectors Level 4: support :has()」這個,主要是有這個功能會對於很多應用很方便,無論是對 designer 在設計上,或是對 javascript developer 的操作。

Chromium 上對應的 commit 在「Supports :has() pseudo class matching」這邊,可以看到目前只實做了一部分:

So this CL only supports :has argument selectors starting with
descendant combinator. Argument selectors starting with other
combinators are not supported yet.
 - .a:has(.b)    : Supported
 - .a:has(> .b)  : Not supported yet
 - .a:has(~ .b)  : Not supported yet
 - .a:has(+ .b)  : Not supported yet

但至少是個進展了...