<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>前端工程 &#8211; Larry的午茶時光</title>
	<atom:link href="https://blog.yuyansoftware.com.tw/category/frontend/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.yuyansoftware.com.tw</link>
	<description></description>
	<lastBuildDate>Mon, 14 Apr 2025 03:55:29 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.yuyansoftware.com.tw/wp-content/uploads/2022/10/favicon-45x45.png</url>
	<title>前端工程 &#8211; Larry的午茶時光</title>
	<link>https://blog.yuyansoftware.com.tw</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>JavaScript ES6 的模組化功能：import, export。建置前端時 require 與 import 有何不同？</title>
		<link>https://blog.yuyansoftware.com.tw/2023/09/javascript-export-import-require/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Sun, 17 Sep 2023 03:08:41 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[gulp]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=16865</guid>

					<description><![CDATA[這篇文章我們來聊一個不新，但重要的議題：JavaScript 的模組化。2015年，JavaScript ECMAScript 2015 發布，也稱為ES6，從此開始，JavaScript 導入了模組化的概念以及語法。]]></description>
										<content:encoded><![CDATA[
<p>這篇文章我們來聊一個不新，但重要的議題：JavaScript 的模組化。</p>



<p>其實 JavaScript 早期只是一個腳本式語言，做做 HTML DOM 的簡單變化而已。也許直接寫在 HTML 裡，也許引用幾支 JS 檔，這樣而已。</p>



<p>2010 年 AngularJS 問世，開啟了 201x 年前端工程的飛速成長，包含各種前端框架的興起，與 Single Page Application (單頁式網站)。AngularJS 後來變成了 Angular，加上 React、Vue.js，這三大家前端框架維持了好一段時間。</p>



<p>延伸閱讀，後來 Laravel 預設的前端框架從 Vue.js 改為使用 Alpine.js (<a href="https://blog.yuyansoftware.com.tw/2021/05/alpine-js-frontend-framework/">我的文章</a>)</p>



<p>2015年，JavaScript <strong>ECMAScript</strong> 2015 發布，也稱為 <strong>ES6</strong>。為什麼是 6 這個數字？是 JavaScript 這個語言的第 6 版。也就是從 ES6 開始，JavaScript 導入了模組化的概念以及語法。</p>



<h2 class="wp-block-heading">ES6 的 import、export</h2>



<p>基本上一個 JS 檔案就是一個模組，用 export 語法，將你想要輸出的變數、函式、物件、類別，都可以輸出。例如</p>



<pre class="wp-block-code"><code>export const your_var = 'test';

export function your_func() {
    // …
}</code></pre>



<p>假設上面檔案叫 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">your_module.js</mark></code>。你可以在 HTML 裡直接輸入 JS 模組，注意一定要寫 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">type="module"</mark></code>，且 import 的後方是大括號</p>



<pre class="wp-block-code"><code>&lt;script type="module"&gt;
    import { your_var, your_func, your_object, your_class } from './your_module.js';

    // 就可以使用 your_var, your_func …
&lt;/script&gt;</code></pre>



<p>或是在另一支 JS (假設名稱是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">abc.js</mark></code>) 裡面 import，HTML 直接引用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">abc.js</mark></code>，注意一樣要寫 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">type="module"</mark></code>。也就是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">your_module.js</mark></code> 的變數輸入到 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">abc.js</mark></code>，並在 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">abc.js</mark></code> 執行</p>



<pre class="wp-block-code"><code>&lt;script type="module" src="./abc.js"&gt;&lt;/script&gt;</code></pre>



<h3 class="wp-block-heading">輸出或輸入都可以改變數名稱</h3>



<p>在輸出時可以改變數名稱</p>



<pre class="wp-block-code"><code>export { your_var as new_name, your_function as new_func };</code></pre>



<p>當然，輸入時就要用新名稱輸入。</p>



<p>輸入時也可以改名</p>



<pre class="wp-block-code"><code>import { your_var as new_name } from "./your_module.js";</code></pre>



<p>這樣在輸入模組就是用新名稱。</p>



<p>還有一種寫法也滿常見的，把整個模組輸入</p>



<pre class="wp-block-code"><code>import * as your_module from './your_module.js';

your_module.func_a();  // 在 your_module.js, func_a 要 named export</code></pre>



<h3 class="wp-block-heading">named 與 default export / import</h3>



<p>以上的 export / import 範例是 <strong>named</strong> export / import (具名輸出/輸入)，還有一種是 <strong>default</strong> export / import。例如</p>



<pre class="wp-block-code"><code>// 輸出
export default your_var;
// 輸入
import new_name from './your_module.js';</code></pre>



<p><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">default export<strong> </strong>最重要的就是在輸出模組「只能出現一次」。</mark>在輸入模組則是任意取名去接。</p>



<p>這樣就是一個最簡單的 export / import 架構了。完整的 export / import 寫法還有很多變形，可以參考 MDN 的 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export" target="_blank" rel="noreferrer noopener nofollow">export 語法文件</a>、<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import" target="_blank" rel="noreferrer noopener nofollow">import 語法文件</a></p>



<h2 class="wp-block-heading">CommonJS 的 require</h2>



<p>目前大部分網站，都是在 Node.js 開發環境 build 前端。常常會看到一個 JS 關鍵字 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">require('...')</mark></code></p>



<p>require 來自於 <strong>CommonJS</strong>，始於開發者的獨立專案。後來 Node.js 用 CommonJS 實作，也採用了 require，直至今日。但必須說明，require 並非 JavaScript ES6 的原生規格。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">require</mark></code> 的參數常常是「不加」檔名，為什麼？例如</p>



<pre class="wp-block-code"><code>require(‘./your_your_module’);</code></pre>



<p>依照 <a href="https://nodejs.org/api/modules.html#modules_file_modules" target="_blank" rel="noreferrer noopener nofollow">Node.js 官方文件</a>，Node.js 會先找 .js、.json、.node。如果你要輸入的不是這3個副檔名，require 參數就要寫檔名全稱 (包含副檔名)。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">require</mark></code> 參數也可以填入 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">package.json</mark></code> 中列出的套件名稱，這樣 Node.js 就會知道要輸入的檔案路徑 (通常是在 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">node_modules</mark></code> 資料夾底下)。</p>



<h2 class="wp-block-heading">建置前端時 require 與 import 的不同</h2>



<p>我們以 Laravel 舉例。基本上 Laravel 是用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">require</mark></code>，因為 Laravel 前端建置基底是 Node.js，用的是 CommonJS module system。當然，Node.js 稍作調整可以支援 ES6 module system，不在這裡討論。</p>



<p>如果你有 <strong>local module</strong> (非 Node.js 核心，非 npm 安裝，開發者自己擺在專案的 js 檔案)，require 跟 import 都可以。</p>



<p>這邊要說明一下，不管是 require 或 import，一般情形只是「執行」該 js 檔案。在建置前端時，是將輸入的模組一起 compile 起來。</p>



<h2 class="wp-block-heading">結語</h2>



<p>本篇回顧了一下 JavaScript ES6 的 import / export，也藉這個機會比較了 Node.js 建置前端時用的 require。</p>



<p>本篇重點並「不在」比較 <strong>CommonJS</strong> 與 <strong>ES6</strong> module system，兩者寫法不同，規格也不同。例如，require 輸入的是整個模組，import 可以輸入一個模組中部分的變數、函式、物件、類別。</p>



<p>import / export 與 require 不是新題目，但卻是現代前端技術很重要的模組化功能。很多前端建置工具是基於 Node.js (例如 Laravel)，require 與 import 也大量被使用，很值得再回顧一下。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Bootstrap 5.3 主要更新：深色模式 Dark mode，自訂 color mode，翻新調色盤色票，新的連結樣式</title>
		<link>https://blog.yuyansoftware.com.tw/2023/06/bootstrap-5-3-features/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Wed, 28 Jun 2023 09:40:44 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=15730</guid>

					<description><![CDATA[Bootstrap 5.3 主要是新增了深色模式 Dark mode，開發者也可以客製自己的 color mode。另外也翻新了調色盤色票 Color Palette，新增了好幾個色票。連結樣式及文件也大幅度翻新了。]]></description>
										<content:encoded><![CDATA[
<p><a href="https://blog.getbootstrap.com/2023/05/30/bootstrap-5-3-0/" target="_blank" rel="noreferrer noopener nofollow">https://blog.getbootstrap.com/2023/05/30/bootstrap-5-3-0/</a><br>前幾個星期 (2023/5/30) Bootstrap 5.3 發布了。每次看到 Bootstrap 新版本的發布，都會有感於時間過的真的很快。以下是我關於 Bootstrap 的文章，大致的時間線：</p>



<ul class="wp-block-list">
<li>2022年7月：<a href="https://blog.yuyansoftware.com.tw/2022/07/bootstrap-5-2-features/">Bootstrap 5.2 主要更新</a></li>



<li>2021年8月：<a href="https://blog.yuyansoftware.com.tw/2021/08/bootstrap-5-1-css-grid-custom-property/">Bootstrap 5.1 主要更新</a></li>



<li>2020年12月：<a href="https://blog.yuyansoftware.com.tw/2020/12/bootstrap-5-features/">Bootstrap 5 主要更新</a></li>



<li>2018年4月：<a href="https://blog.yuyansoftware.com.tw/2018/04/bootstrap-4-flex/">Bootstrap 4 Flex</a> (那時 Bootstrap 4.1 發布)</li>



<li>2017年8月：<a href="https://blog.yuyansoftware.com.tw/2017/08/bootstrap-4-beta/">Bootstrap 4 主要更新</a></li>
</ul>



<p>撰文的現在是2023年6月。可以看到每一個 minor version 的更新，就是半年～1年；major version 的更新，是好幾年一版。所以每次寫 Bootstrap，就代表好多歲月又過去了，時間真的過得太快。</p>



<p>以下是 Bootstrap 5.3 的主要更新：</p>



<h2 class="wp-block-heading">深色模式 Dark mode，自訂新的 color mode</h2>



<p>Bootstrap 核心已經重新設計，以支援 Dark mode。並新增了關於 Color Mode 的文件 (5.2 沒有)<br><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.3/customize/color-modes/" target="_blank">https://getbootstrap.com/docs/5.3/customize/color-modes/</a></p>



<p>Bootstrap 5.3 不但支援 Dark mode，也允許開發者設計自己的 color mode。語法上，在一開始的 html tag 下 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">data-bs-theme</mark></code>，例如</p>



<pre class="wp-block-code"><code>&lt;html lang="en" data-bs-theme="dark"&gt;
  &lt;!-- ... --&gt;
&lt;/html&gt;</code></pre>



<p>你也可以在特定的元件下 color mode，例如 dropdown menu</p>



<pre class="wp-block-code"><code>&lt;div class="dropdown" data-bs-theme="dark"&gt;
  &lt;!-- ... --&gt;
&lt;/div&gt;</code></pre>



<p>這樣無論上方 html tag 的 color mode，你的 dropdown menu 就會切換成 Dark mode。</p>



<p>當然，如果你想要本來「亮底」的樣式，設定 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">data-bs-theme="light"</mark></code>，或是將來你自己客製的樣式。</p>



<p>Light / Dark mode 都定義在 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_root.scss</mark></code>，包含如果你將來要新增自己的 color mode，也是定義在這支檔案。</p>



<p>目前 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_root.scss</mark></code> 定義的是 CSS 變數，你也可以在其中指定特定元件的樣式。例如</p>



<pre class="wp-block-code"><code>@include color-mode(dark) {
  ...
  .element {
    color: var(--bs-primary-text-emphasis);
    background-color: var(--bs-primary-bg-subtle);
  }
  ...
}</code></pre>



<p>另外，如果你重設這個 SCSS 變數</p>



<pre class="wp-block-code"><code>$color-mode-type: media-query; // default 是 "data"</code></pre>



<p>上面那段 SCSS 會編譯成</p>



<pre class="wp-block-code"><code>@media (prefers-color-scheme: dark) {
  .element {
    color: var(--bs-primary-text-emphasis);
    background-color: var(--bs-primary-bg-subtle);
  }
}</code></pre>



<p>這樣就不是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">data-bs-theme</mark></code> 設定 scope 的概念，而是 media query <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">prefers-color-scheme</mark></code>，隨使用者作業系統調整亮/暗模式。</p>



<p>有一些 Dark mode 的 CSS 變數是定義在 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_variables-dark.scss</mark></code>。當然，你可以修改再重新編譯。如果你要新增 color mode，官方文件也建議新增新的 scss 檔案，例如 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_variables-blue.scss</mark></code>。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_variables-dark.scss</mark></code> 中大量的使用 Bootstrap 內建的 SCSS function <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">shade-color()</mark></code>、<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">tint-color()</mark></code>，也就是拿原始的調色盤色票去做深淺變化。如果你要整個換色系的話，修改原始色票再重新編譯，<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_variables-dark.scss</mark></code> 這支檔案就會自動幫你做深淺變化了。</p>



<h2 class="wp-block-heading">翻新調色盤色票 Color Palette</h2>



<p>文件也做大幅更新，第一節 Colors 是 5.3 新增的。<br><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.3/customize/color/" target="_blank">https://getbootstrap.com/docs/5.3/customize/color/</a></p>



<p>新增 secondary、tertiary 兩個色票。舉例來說，Bootstrap 5.3 Light mode 中這幾個變數 <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">(數值是 Bootstrap 5.3 定義的，之後版本不一定會改)</mark></p>



<pre class="wp-block-code"><code>--bs-body-color-rgb: 33,37,41;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-tertiary-color: rgba(33, 37, 41, 0.5);</code></pre>



<p>因為是 Light mode，背景是白的，隨著 alpha 值越透明，tertiary 文字顏色最淡。</p>



<p>Bootstrap 5.3 Dark mode 中這幾個變數的數值</p>



<pre class="wp-block-code"><code>--bs-body-color-rgb: 173,181,189;
--bs-secondary-color: rgba(173, 181, 189, 0.75);
--bs-tertiary-color: rgba(173, 181, 189, 0.5);</code></pre>



<p>因為是 Dark mode，背景是黑的，隨著 alpha 值越透明，也就是 tertiary 文字顏色最深。</p>



<p>進一步說明，以目前 (2023年6月) Bootstrap 官網文件來說，如果是 Dark mode，一般文字顏色就是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">--bs-body-color</mark></code>，secondary / tertiary 多了兩個不同灰階 (顏色更深) 的選擇。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.bg-body-secondary</mark></code>、<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.bg-body-tertiary</mark></code> 就不是深淺灰階的概念，是由 Bootstrap 直接定義值，用來搭配 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">--bs-secondary-color</mark></code>、<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">--bs-tertiary-color</mark></code> 的顏色。&nbsp;</p>



<p>另外還新增 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">{color}-bg-subtle</mark></code>、<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">{color}-border-subtle</mark></code>、<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">{color}-text-emphasis</mark></code> 這幾個顏色。</p>



<p>subtle 這邊指的是暗的、淡的。比如說 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.bg-success</mark></code> 是軟體操作成功的綠色，<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.bg-success-subtle</mark></code> 在 Light mode 就是淡綠色，在 Dark mode 就是墨綠色。</p>



<p><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.3/customize/color/" target="_blank">https://getbootstrap.com/docs/5.3/customize/color/</a><br>文件也列出 Bootstrap 所有可用的色票，包含紅橙黃綠藍靛紫，以及各自的灰階，如果要很快的找一個色票使用，可以參考這裡。</p>



<h2 class="wp-block-heading">新的 Link 連結樣式</h2>



<p>新的 Link 文件 (Bootstrap 5.2 沒有)，包含透明度 opacity，底線 underline 等樣式。<br><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.3/utilities/link/" target="_blank">https://getbootstrap.com/docs/5.3/utilities/link/</a></p>



<p>新的 Icon Link 文件 (Bootstrap 5.2 沒有)<br><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.3/helpers/icon-link/" target="_blank">https://getbootstrap.com/docs/5.3/helpers/icon-link/</a></p>



<p>可以輕易的在連結的前或後，加上小圖。如果再加上 css <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.icon-link-hover</mark></code>，滑鼠 hover 時小圖會有小動畫。</p>



<pre class="wp-block-code"><code>&lt;a class="icon-link icon-link-hover" href="#"&gt;
  Icon link
  &lt;svg&gt;...&lt;/svg&gt;
&lt;/a&gt;</code></pre>



<p>新的 css <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.focus-ring</mark></code>，讓元件在 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">:focus</mark></code> 狀態下，不要顯示預設的 outline，而是變成 box-shadow，這樣可以更好的讓開發者客製化。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.focus-ring</mark></code> 也是 Bootstrap 5.3 的新文件<br><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.3/helpers/focus-ring/" target="_blank">https://getbootstrap.com/docs/5.3/helpers/focus-ring/</a></p>



<h2 class="wp-block-heading">總結</h2>



<p>這次 Bootstrap 5.3 更新主要是在深色模式 Dark mode，還有各種色系、色票的更新，並沒有大的架構或排版上的更新。</p>



<p>Dark mode 的確是近幾年的 CSS 主題：Windows / Mac / Android / iPhone / iPad 作業系統都支援 Dark mode，當然細緻一點的 web app，應該也要支援 Dark mode。</p>



<p>調色盤色票的更新，則是讓我們再 review 一次，未來可不可用 Bootstrap 內建的色票架構。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>LINE LIFF (LINE Frontend Framework) 前端框架，如何理解、設定與使用 LIFF app</title>
		<link>https://blog.yuyansoftware.com.tw/2023/06/liff-app-line-frontend-framework/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Sat, 03 Jun 2023 13:01:27 +0000</pubDate>
				<category><![CDATA[LINE]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[網路科技]]></category>
		<category><![CDATA[客製化網站系統]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=15238</guid>

					<description><![CDATA[LINE 應該是台灣人最常使用的通訊軟體。LIFF (LINE Frontend Framework) 是一個 LINE 提供的 web app 平台。在 LINE app 中點開 LIFF，直接用戶登入後就可以開始應用。]]></description>
										<content:encoded><![CDATA[
<p>圖片來源 <a href="https://developers.line.biz/en/docs/liff/overview/" target="_blank" rel="noreferrer noopener nofollow">https://developers.line.biz/en/docs/liff/overview/</a></p>



<p>LINE 應該是台灣人最常使用的通訊軟體。LIFF (<strong>LINE Frontend Framework</strong>) 是一個 LINE 提供的 web app 平台。</p>



<p>LIFF app 我們可以想成是一個嵌入 LIFF SDK (js) 的網頁，使用者在自己的 LINE 點開該網頁時，直接 Line login 到該網頁。</p>



<p>一般 LINE 聊天機器人，與用戶交談一定是「問答式訊息」的形式。LIFF 因為是網頁的形式，可以達成一些問答式訊息做不到的效果。另外，LIFF 因為是 LINE 自家的東西，高度整合，在 LINE 裡彈出 LIFF 網頁的用戶體驗，也比轉址到其他網頁好。</p>



<h2 class="wp-block-heading">如何建立 LIFF app</h2>



<p>要使用 LIFF，到 LINE <strong>Developer Console</strong> 建立一個類型為「LINE Login」的 channel。目前 (2023年6月) 一定要類型為「LINE Login」的 channel (Messaging API 不行)。</p>



<p>在「LINE Login」channel 切到 LIFF tab，可以新增一個 LIFF app。也可以新增多個 LIFF app，會列在這頁。</p>



<p>如果在一個 channel 底下新增了<strong>多個</strong> LIFF app。LINE 在前幾天有一個公告，2023/5/23 之後新增的 LIFF app，會以新增日期新到舊排列，2023/5/23 以前新增的 LIFF app 則沒有固定的排序規則。<br><a href="https://developers.line.biz/en/news/2023/05/23/order-of-liff-apps/" target="_blank" rel="noreferrer noopener nofollow">https://developers.line.biz/en/news/2023/05/23/order-of-liff-apps/</a></p>



<h3 class="wp-block-heading">新增 LIFF app 時的欄位</h3>



<p>新增 LIFF app 時，填入你想要的 LIFF app 名稱。選擇彈出的 Size：Full / Tall / Compact，三擇一。</p>



<p>彈出 Size 的選項分別是：Full 佔據手機螢幕 100%，Tall 佔據手機螢幕「約」80%，Compact 佔據手機螢幕「約」50%。</p>



<p>填入你的 <strong>Endpoint URL</strong>。這是你要 host 實體網頁的 URL，這實體網頁就是所謂的 LIFF web app。輸入的網址要 https 開頭。</p>



<p>接著選擇用戶授權 LIFF SDK 的不同權限 Scopes：profile / chat_message.write / openid，可以多選。</p>



<p>以 profile 舉例，如果有勾 profile 且用戶使用時同意，這樣 LIFF app 就可以使用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">liff.getProfile()</mark></code> 或 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">liff.getFriendship()</mark></code> 兩個 API。</p>



<p>接著選擇 Bot link feature: On (Normal) / On (Aggressive) / Off，三擇一。</p>



<p>一般來說選 On (Normal)，這會在 LIFF app 用戶使用同意這一頁，增加一個將此&nbsp;LINE 官方帳號 (Official Account, OA) 增加為好友的選項。</p>



<h3 class="wp-block-heading">新增完了會得到一個 LIFF ID 跟 LIFF URL</h3>



<p>新增完了會得到一個 LIFF ID 跟 LIFF URL。以目前來說 (2023年6月)，LIFF URL 的格式是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">https://liff.line.me/your_liff_id</mark></code>&nbsp;</p>



<p>使用者觸發此 LIFF URL 時，LINE 會轉址到之前填的 <strong>Endpoint URL</strong>，並提供 LIFF web app。當然，轉址時 LINE server 會確認點擊來源、確認是哪個 LINE 用戶，以及 Developer Console 的後台設定，例如彈出高度的設定。</p>



<h2 class="wp-block-heading">LIFF 網頁的製作</h2>



<p><a href="https://developers.line.biz/en/docs/liff/developing-liff-apps/" target="_blank" rel="noreferrer noopener nofollow">https://developers.line.biz/en/docs/liff/developing-liff-apps/</a><br>LIFF 網頁的製作，參考這份官方文件。基本上一開始一定要 init</p>



<pre class="wp-block-code"><code>liff.init({
    liffId: 'your_liff_id’,
})
.then(() =&gt; {
    // start to use LIFF's api
})
.catch((err) =&gt; {
    console.log(err);
});</code></pre>



<p>在 LIFF browser (也就是在 LINE App 中點開)，做完 init 就直接已經 login 了。在 external browser (也就是一般手機/電腦瀏覽器) 要另 call <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">liff.login()</mark></code></p>



<p>因為我們主要使用場景是在 LINE App，暫時不談 external browser。</p>



<p>如果在 LIFF browser 點開，init / login 成功了，我們可以直接 call <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">liff.getProfile()</mark></code>，就可以拿到 LINE user id，顯示名稱、縮圖。還記得文章上方 Developer Console 設定時，要選一個 Scopes，有勾 profile 才能使用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">liff.getProfile()</mark></code>。</p>



<p>詳細 LIFF API 規格參考官方文件<br><a href="https://developers.line.biz/en/reference/liff/" target="_blank" rel="noreferrer noopener nofollow">https://developers.line.biz/en/reference/liff/</a></p>



<h3 class="wp-block-heading">init / login 完成了，你的應用就可以開始了</h3>



<p>init / login 完成了，你的應用就可以開始了。例如，如果需要 LIFF app 與你的系統主機作互動，用 access token 或 ID token 當溝通方式。</p>



<pre class="wp-block-code"><code>// 二擇一，如果需要回傳 server
liff.getAccessToken();
liff.getIDToken(); // 需要 Scope openid 的權限</code></pre>



<p>完整的互動方式請參考官方文件，有 sequence diagram<br><a href="https://developers.line.biz/en/docs/liff/using-user-profile/" target="_blank" rel="noreferrer noopener nofollow">https://developers.line.biz/en/docs/liff/using-user-profile/</a></p>



<p>以上大概就是 LIFF app 的架構。建立一個實體網頁 → 在 Developer Console 中設定 → 在實體網頁嵌入 LIFF SDK 並初始成功 → 在 LIFF browser (也就是在 LINE App 中) 點開 <strong>LIFF URL</strong>，建立好的 LIFF app 就會彈出了。</p>



<p>接著就是建立你的系統需求、應用、以及變化。</p>



<h2 class="wp-block-heading">結論</h2>



<p>本篇文章走了一遍 LIFF app 大的架構與理解，細節有需要請參考官方文件。</p>



<p><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">LIFF 因為是網頁的形式，可以達成一些「問答式訊息」做不到的效果。</mark>在 LINE app 中點開 LIFF，直接用戶登入後就可以開始應用。網頁開發上應該也與一般網頁無異 (不要使用 LIFF browser 不支援的技術)。</p>



<p>另外，LIFF 因為是 LINE 自家的東西，高度整合，在 LINE 裡彈出 LIFF 網頁，用戶體驗應該也比轉址其他網頁好。</p>



<p><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">很多服務業，例如餐飲業或美業，如果有建立 FB/IG 粉絲頁、Google 商家，其實並不需要也沒有官網。</mark>此時 LINE 的應用就派上用場了，例如查詢預約及會員點數。</p>



<p>其實很多行業並不需要官網，我們要在這個認知下，做系統的規劃。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Interop 2023，四大瀏覽器繼續合作，解決瀏覽器相容性的問題並推動新技術</title>
		<link>https://blog.yuyansoftware.com.tw/2023/03/interop-2023-browser-compatibility-css/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Sun, 19 Mar 2023 04:01:26 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[網路科技]]></category>
		<category><![CDATA[Link5]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=14412</guid>

					<description><![CDATA[從 Interop 2022 開始，四大瀏覽器 (Chrome, Edge, Safari, Firefox) 一起合作解決瀏覽器相容性的問題，已經有了明確的成果。Interop 2023 四大瀏覽器繼續合作，推動 Web 技術的進步，與降低瀏覽器相容性的問題。]]></description>
										<content:encoded><![CDATA[
<p>去年 (2022) 開始四大瀏覽器 (Chrome, Edge, Safari, Firefox) 開始合作，一起解決瀏覽器相容性的問題，也因此這四家瀏覽器廠商一起成立了一個 Interop 2022 專案。</p>



<p><strong>Interop 2022</strong> 主要專注在 15 個瀏覽器相容性的問題。參考我去年 (2022) 的文章 <br><a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2022/04/compat-2021-interop-2022-browser-compatibility/" target="_blank">從 Compat 2021 到 Interop 2022，史上第一次所有的主流瀏覽器，合作解決相容性的問題</a></p>



<p><a href="https://web.dev/interop-2023/" target="_blank" rel="noreferrer noopener">https://web.dev/interop-2023/</a><br>今年的 <strong>Interop 2023</strong> 主要專注在以下領域</p>



<ol class="wp-block-list">
<li>Border Image in CSS</li>



<li>Color Spaces and Functions in CSS</li>



<li>Container Queries (@container)</li>



<li>Containment in CSS</li>



<li>CSS Pseudo-classes</li>



<li>Custom Properties (@property)</li>



<li>Flexbox</li>



<li>Font feature detection and palettes</li>



<li>Forms</li>



<li>Grid</li>



<li>:has()</li>



<li>Inert</li>



<li>Masking in CSS</li>



<li>Math Functions in CSS</li>



<li>Media Queries</li>



<li>Modules in Web Workers</li>



<li>Motion Path in CSS Animations</li>



<li>Offscreen Canvas</li>



<li>Pointer and mouse Events</li>



<li>URL</li>



<li>Web Compat 2023</li>



<li>Web Codecs (video)</li>



<li>Web Components</li>
</ol>



<p>Interop 有一個網頁，測試四大瀏覽器每個版本對於新規格的支援度，像是軟體開發的 auto test 面板，很清楚很有趣。<br><a href="https://wpt.fyi/interop-2023" target="_blank" rel="noreferrer noopener">https://wpt.fyi/interop-2023</a></p>



<p>可以看到關於 <strong>Interop 2022</strong> 的重點領域：Cascade Layers、Dialog Element、position sticky、aspect-ratio、Viewport Units，等，四大瀏覽器已經有很高的支援度了，也因此沒有出現在 Interop 2023 的重點項目。</p>



<p>延伸閱讀：我之前關於 <a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2022/02/css-cascade-layers-specificity/" target="_blank">Cascade Layers</a>、<a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2022/12/css-viewport-units-large-small-dynamic/" target="_blank">Viewport Units</a> 的文章</p>



<p><strong>Interop 2023</strong> 的重點項目，例如 <strong>Container Queries</strong>，目前 (2023年3月) 四大瀏覽器已全部支援。它是傳統 media query 的加強版，可以指定元件 container，並依照此 container 的大小下不同的 CSS 語法。</p>



<p><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">在不同 container 大小可以下不同 CSS 語法，可以大幅增加 component reusable。</mark></p>



<p><strong>:has() selector</strong> 可以選擇有某種 child 元素的 parent 元素，或是該元素有某種 sibling 元素。目前 (2023年3月) Firefox 還不支援。</p>



<p><strong>Custom Properties</strong> 已經是一個大家常用，而且新手幾乎一定要學的語法了。Bootstrap 5 開始也將 Custom Properties 寫法納入到核心。Bootstrap 5 beta 1 是2020年12月發布的，可想而知 Custom Properties 已經通用了多久，Bootstrap 才決定採用，再加開發的時間，2020年12月才發布 beta 1。</p>



<p>既然 Custom Properties 上線以久，<strong>Interop 2023</strong> 關注的是它的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@property</mark></code> 語法，目前 (2023年3月) Safari 和 Firefox 都不支援。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@property</mark></code> 語法可以將原本的 CSS 變數，擴展成資料結構。你可以指定這個變數的類型 (syntax) 與初始值 (initial-value)，後續開發者指定 CSS 變數值時，會執行 type check，如果 invalid，會 fallback 到 initial-value。</p>



<p><strong>CSS Masking</strong> 也是被「挖出來」重新討論的題目。CSS Masking (mask-image) 是一個存在很久的東西了，的確好像長期以來不是討論的重點，開發者使用起來也抖抖的，不知道是不是完整的規格，會不會有瀏覽器相容性的問題。</p>



<p>我在 2015 年有一篇文章，那時 CSS Masking 已經出來，而且已經「擺在那邊」很久了：<a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2015/03/css-mask-clip/" target="_blank">CSS 的演變歷程，Mask &amp; Clip</a></p>



<p><strong>Interop 2023</strong> 還有很多要討論的題目，這邊就不一一列舉。</p>



<h4 class="wp-block-heading">結論</h4>



<p>撰文的現在是2023年3月，201x 有幾年 CSS 的發展有停滯，但近幾年隨著 CSS Grid、Custom Properties、甚至 Cascade Layers 等新技術的上線，似乎 CSS 這個語言又有了很強的進步動能。</p>



<p>larry 覺得近幾年 CSS 可以進步這件事，跟微軟目前的 CEO <strong>Satya Nadella</strong> 與他的領導團隊有關。他們讓 IE 退休，用 Chromium 當核心重做 Edge，瀏覽器所有規格也跟 Google、Mozilla 合作。試想，如果現在還有很多公司用 Windows IE 瀏覽器，你要怎麼去推 CSS 科技進步？</p>



<p>包含之前的文章 <a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2022/04/compat-2021-interop-2022-browser-compatibility/" target="_blank">Interop 2022</a>，還有 <a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2023/03/openai-chatgpt-microsoft-google-search/" target="_blank">ChatGPT 是否會取代 Google 搜尋？</a> 都表達了我對微軟 CEO <strong>Satya Nadella</strong> 的敬意。larry 開公司很久了，我看得出來他的商業判斷很厲害。</p>



<p>很高興歷史走到現在，這幾家巨頭企業在瀏覽器的部分是傾向合作，而不是對抗。也因此 CSS 這個語言，甚至整個網路科技的發展，都是不斷往前的。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>新的 CSS Viewport Units (large/small/dynamic)，目前四大瀏覽器已全部支援！</title>
		<link>https://blog.yuyansoftware.com.tw/2022/12/css-viewport-units-large-small-dynamic/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Tue, 13 Dec 2022 05:11:40 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[Link5]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=13180</guid>

					<description><![CDATA[最近 Chrome 108 版宣布開始支援新的 Viewport Units：lvh, svh, dvh。這也是 Interop 2022 的第 9 個工作項目。Chrome 開始支援後，目前四大瀏覽器都已支援新的 Viewport 單位。]]></description>
										<content:encoded><![CDATA[
<p>圖片來源 <a rel="noreferrer noopener" href="https://web.dev/viewport-units/" target="_blank">https://web.dev/viewport-units/</a></p>



<p>larry 之前有一篇關於 <strong>Interop 2022</strong> 的文章<br><a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2022/04/compat-2021-interop-2022-browser-compatibility/" target="_blank">從 Compat 2021 到 Interop 2022，史上第一次所有的主流瀏覽器，合作解決相容性的問題</a></p>



<p><a rel="noreferrer noopener" href="https://web.dev/viewport-units/" target="_blank">https://web.dev/viewport-units/</a><br>幾天前 web dev 有一篇文章，提到了 <strong>Interop 2022</strong> 的第 9 個工作項目：新的 Viewport Units，lvh, svh, dvh。也很高興宣布四大瀏覽器都支援新的 Viewport 單位。</p>



<p>Viewport 長度單位的官方文件在這裡<br><a rel="noreferrer noopener" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths" target="_blank">https://drafts.csswg.org/css-values-4/#viewport-relative-lengths</a></p>



<p>這份文件是 <strong>CSS Values and Units Module Level 4</strong>，這份文件從 Level 3 到撰文的此時 (2022年12月) 已經出到 Level 5。</p>



<p>除了我們熟知的 vw, vh，還有 vmin, vmax。vmin 代表 vw / vh 兩者中比較小的，也就是當 viewport 是寬的 (vw &gt; vh)，vmin 代表 vh。當 viewport 是高的，vmin 代表 vw。vmax 也是一樣邏輯，取 vw / vh 兩者中比較大的。</p>



<p>以上這部分是四大瀏覽器早就支援的。</p>



<p>新的 Viewport 單位主要為了解決一般手機瀏覽器，使用者在捲動網頁時，網址列/工具列會自動縮放的問題。</p>



<p>例如 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">height: 100vh</mark></code> 的區塊，如果手機瀏覽器網址列/工具列都顯示出來，<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">height: 100vh</mark></code> 的區塊其實是比<strong>可視面積</strong>高的。</p>



<p>上面 <strong>Level 4</strong> 文件新定義了 3 個新單位：</p>



<ul class="wp-block-list">
<li>lv*：large viewport size，所有瀏覽器 UI 縮起來時，最大的網頁可視面積。當設定 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">height: 100lvh</mark></code>，且瀏覽器 UI 展開時，有可能會遮住網頁。</li>



<li>sv*：small viewport size，所有瀏覽器 UI 展開時，最小的網頁可視面積。當設定 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">height: 100svh</mark></code>，且瀏覽器 UI 縮起來時，有可能會出現空白面積。</li>



<li>dv*：dynamic viewport size，除了瀏覽器 UI 之外，網頁的可視面積。隨使用者操作，dv* 會動態更新成 lv* 或 sv*。也因為 dv* 會動態更新，使用者操作時可能網頁內容會有奇怪縮放 (如果某一區塊是用 dvh 當單位)。</li>
</ul>



<p>原本的 vw, vh 指的是 “<mark style="background-color:rgba(0, 0, 0, 0);color:#999999" class="has-inline-color">UA (User Agent) default viewport size</mark>”。上面 <strong>Level 4</strong> 文件指出 default viewport size 可以是 large viewport size 或 small viewport size，或 large / small 之間的值。也就是依照不同手機瀏覽器不一定。</p>



<p>當然，如果不影響你的頁面，不用煩惱。但如果你有手機應用，又正好有 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">height: 100vh</mark></code> 之類，就要測試一下 large / small / dynamic viewport 單位。</p>



<p>large / small / dynamic viewport 單位，四大瀏覽器 Chrome 108，Firefox 101，Edge 108，Safari 15.4 都已經支援 (以目前2022年12月來講，都算新版瀏覽器)。</p>



<p>上面 web dev 文章有提到 3 點要特別注意：</p>



<ol class="wp-block-list">
<li>所有 viewport 單位都「沒有」考慮 scrollbar 的寬度。如果是傳統 scrollbar 的系統，<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">width: 100vw</mark></code> 有可能會超出可視面積。</li>



<li>dynamic viewport 單位值的更新問題。尤其當網頁的更新速度 (frame rate) 小於瀏覽器 UI 縮放的更新速度，dv* 的區塊可能會有奇怪縮放 (本文上方有提到)。</li>



<li>手機彈出的虛擬鍵盤「不算」瀏覽器 UI，因此不影響 viewport 單位的值。</li>
</ol>



<h4 class="wp-block-heading">結論</h4>



<p>從 <strong>Compat 2021</strong> 到 <strong>Interop 2022</strong>，四大瀏覽器開始合作，很明顯的看到 CSS 語言的整合與進展，這對網路科技的發展，絕對是一件好事。</p>



<p>如果讀者有稍微瀏覽一下 <strong>CSS Values and Units Module Level 4</strong> 的文件，viewport 單位的更新其實是一個細節更新，但文件裡有多少備註，多少版本。任何一丁點科技的演進，都是不知道多少人智慧的結晶。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Laravel Vite：繼 Laravel Mix 之後新的前端檔案管理工具</title>
		<link>https://blog.yuyansoftware.com.tw/2022/12/laravel-vite/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Sat, 10 Dec 2022 11:53:49 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[gulp]]></category>
		<category><![CDATA[Link7]]></category>
		<category><![CDATA[新功能]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=13078</guid>

					<description><![CDATA[從 Laravel 9.19 開始 (2022/6/30)，Laravel 前端檔案管理工具從 Mix 改為 Vite。Laravel Mix 的底層是 Webpack，而 Vite 是基於原生 JavaScript ESM 的前端開發工具。Vite 在熱更新時 (HMR) 是先 refresh 瀏覽器，才編譯與該頁面有關的檔案。]]></description>
										<content:encoded><![CDATA[
<p>從 Laravel 5.4 開始 (2017/1/24)，前端檔案管理工具就是 <strong>Laravel Mix</strong>，我當年還有一篇關於 <a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2017/04/laravel-mix/" target="_blank">Laravel Mix 的文章</a></p>



<p>Laravel 9.19 開始 (2022/6/30)，Laravel 前端檔案管理工具從 Laravel Mix 改為 <strong>Vite</strong>。</p>



<p>每次寫關於軟體工程演進類的文章，都會有感於時間過得真的太快。2017~2022，五年多就這樣過去了。五年的時間，希望大家在人生中都有累積些什麼。</p>



<p>Laravel Mix 的底層是 <strong>Webpack</strong>，在 Laravel 根目錄會有 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">package.json</mark></code>, <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">webpack.mix.js</mark></code> 兩支檔案。執行</p>



<pre class="wp-block-code"><code>npm install</code></pre>



<p>會依照 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">package.json</mark></code> 去安裝套件到你的開發環境。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">package.json</mark></code> 中有一個 “scripts” 欄位，定義了很多 npm 指令，並將 npm 指令轉成 mix 指令。mix 指令就會去跑 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">webpack.mix.js</mark></code> 這支檔案裡的 script，包含 compile css / js。</p>



<p><strong>Laravel Vite</strong> 是基於 <a rel="noreferrer noopener" href="https://vitejs.dev/" target="_blank">Vite</a>，是一個基於原生 JavaScript ESM 的前端開發工具。與 Webpack 機制上不同的是，Webpack 一律依照 script 打包全部檔案素材 (dev mode 也是打包全部)。</p>



<p>而 Vite 在<strong>熱更新</strong>時 (hot module replacement，HMR)，是先 refresh 瀏覽器，檢查現在前端頁面有關的檔案是否有更新，如果有，才編譯與該頁面有關的檔案 (而不是每次都全部打包)。因此在開發階段，尤其是大型專案，會大幅加速開發時間。</p>



<p><strong>Laravel Vite</strong> 一樣有 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">package.json</mark></code>，一樣要跑 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">npm install</mark></code>。只是根目錄 script 檔案不是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">webpack.mix.js</mark></code>，改為用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">vite.config.js</mark></code>。</p>



<p>Laravel Vite 的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">package.json </mark></code>中一樣有 “scripts” 欄位：</p>



<pre class="wp-block-code"><code>npm run dev  // 轉成 “vite”
npm run build  // 轉成 "vite build"</code></pre>



<p>vite 指令就會去跑 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">vite.config.js</mark></code> 這支檔案裡的 script，預設是</p>



<pre class="wp-block-code"><code>export default defineConfig({
    plugins: &#91;
        laravel({
            input: &#91;
                'resources/sass/app.scss',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
});</code></pre>



<p>入口的 css / js 一樣是 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">resources/sass/app.scss</mark></code>, <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">resources/js/app.js</mark></code>。注意有一個設定 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">refresh: true</mark></code>，這代表在執行 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">npm run dev</mark></code> 時，如果底下這幾個路徑檔案有更新</p>



<ul class="wp-block-list">
<li>app/View/Components/**</li>



<li>lang/**</li>



<li>resources/lang/**</li>



<li>resources/views/**</li>



<li>routes/**</li>
</ul>



<p>瀏覽器已 load 的頁面會整頁 refresh。以上是預設的監聽路徑，你也可以將自己想監聽的檔案路徑設定給 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">refresh</mark></code> 參數 (以設定 array 代替 true)，這樣 Vite 就會監聽你定義的路徑。</p>



<p>跟之前一樣 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">app.scss</mark></code> 中預設 import 隔壁的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">_variables.scss</mark></code>。</p>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">app.js</mark></code> 中預設 import 隔壁的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">bootstrap.js</mark></code>，在其中 load 你需要的套件，例如：jQuery，Bootstrap，Vue，等。</p>



<p>在前端檔案加一行 (與 <strong>Mix</strong> 不同，<strong>Vite </strong>引用 css / js 在同一行)</p>



<pre class="wp-block-code"><code>@vite(&#91;'resources/sass/app.scss', 'resources/js/app.js'])</code></pre>



<p>就可以將 compile 好的 css / js 引入 (並加 preload 屬性)。如果是 Build Mode (<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">npm run build</mark></code>)，css / js 檔名會加上版本號 (auto-versioning)。</p>



<p>目前如果先安裝 laravel/ui，build 出來的 css / js 會包含 Bootstrap 5.2.3，是目前 (2022年12月) Bootstrap 的最新版。</p>



<p>Vite 也可以處理前端素材檔案，例如圖檔跟字型檔。在 JS 的入口處 (<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">app.js</mark></code>) 寫入</p>



<pre class="wp-block-code"><code>import.meta.glob(&#91;
  '../images/**',
  '../fonts/**',
]);</code></pre>



<p>執行 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">npm run build</mark></code>，這樣 Vite 就會將素材檔名編碼過，並移到 public folder 底下。前端要用素材檔可以這樣寫</p>



<pre class="wp-block-code"><code>&lt;img src="{{ Vite::asset('resources/images/logo.png') }}"&gt;
{{-- &lt;img src="http://your-url.com/build/assets/logo.1234ooxx.png"&gt; --}}</code></pre>



<h4 class="wp-block-heading">結論</h4>



<p>從 Webpack 到 Vite，底層是完全不同了。但可以看出來 <strong>Laravel Vite</strong> 創作時，作者盡量不動 Laravel 的架構，與之前一樣的 css / js 入口檔案。</p>



<p>Vite config 當然有一些獨立的功能和寫法。既然 Laravel 決定改用 Vite 了，我們應該也要隨之學習和習慣 Vite 的使用。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Bootstrap 5.2 主要更新：幾乎全部元件都用 CSS 變數實作，新的 CSS build sequence</title>
		<link>https://blog.yuyansoftware.com.tw/2022/07/bootstrap-5-2-features/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Fri, 29 Jul 2022 03:36:00 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=11285</guid>

					<description><![CDATA[Bootstrap 5.2 沒有大的架構更新，就是多了一些 CSS helper class。CSS 變數的使用幾乎遍及所有元件，所以 CSS 變數的使用越來越重要。以及調整了 Bootstrap CSS build sequence。]]></description>
										<content:encoded><![CDATA[
<p>圖片來源 <a href="https://blog.getbootstrap.com/2022/05/16/using-bootstrap-css-vars/" target="_blank" rel="noreferrer noopener nofollow">Bootstrap官方部落格</a></p>



<p><a href="https://blog.getbootstrap.com/2022/07/19/bootstrap-5-2-0/" target="_blank" rel="noreferrer noopener nofollow">https://blog.getbootstrap.com/2022/07/19/bootstrap-5-2-0/</a><br>前幾天 (2022/7/19) Bootstrap 5.2 發布了。每次看到 Bootstrap 新版本的發布，都會有感於時間過的真的很快。以下是我關於 Bootstrap 的文章，大致的時間線：</p>



<ul class="wp-block-list">
<li>2021年8月：<a href="https://blog.yuyansoftware.com.tw/2021/08/bootstrap-5-1-css-grid-custom-property/">Bootstrap 5.1 主要更新</a></li>



<li>2020年12月：<a href="https://blog.yuyansoftware.com.tw/2020/12/bootstrap-5-features/">Bootstrap 5 主要更新</a></li>



<li>2018年4月：<a href="https://blog.yuyansoftware.com.tw/2018/04/bootstrap-4-flex/">Bootstrap 4 Flex</a> (那時 Bootstrap 4.1 發布)</li>



<li>2017年8月：<a href="https://blog.yuyansoftware.com.tw/2017/08/bootstrap-4-beta/">Bootstrap 4 主要更新</a></li>
</ul>



<p>撰文的現在是2022年7月。可以看到每一個 Bootstrap minor version 的更新，就是半年～1年。更甭論 major version 的更新是好幾年一版。所以每次寫 Bootstrap，就代表好多歲月又過去了。</p>



<p>以下是 Bootstrap 5.2 的主要更新：</p>



<h2 class="wp-block-heading">官網首頁重新設計，以及文件網頁優化</h2>



<p>重新設計了 Bootstrap 官網首頁，文件網頁也有多處優化，包含左側 menu 的重組，文件搜尋的使用體驗，等等。</p>



<h2 class="wp-block-heading">更新按鈕樣式</h2>



<p>border-radius 調大了一點，雖然按鈕大小跟之前一樣，看起來好像 padding 變小而文字更突出的感覺。</p>



<h2 class="wp-block-heading">幾乎全部元件都用 CSS 變數 (custom property) 實作</h2>



<p>比 Bootstrap 5.1 更多的 CSS 變數實作，幾乎全部元件都是。</p>



<h2 class="wp-block-heading">新的 _maps.scss</h2>



<p>有一個新的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_maps.scss</mark></code> (Bootstrap 5.1 沒有)。<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">_maps.scss</mark></code> 將一些 Sass map 從 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">_variables.scss</mark></code> 抽出。修正對原始 Sass map 修改時，基於原始 Sass map 擴展的 map，不會繼承這些修改的問題。</p>



<p>舉例來說 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$utilities-colors</mark></code> 基於 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$theme-colors</mark></code> 擴展。因為 Bootstrap 5.1 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$utilities-colors</mark></code> 在 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">_variables.scss</mark></code> 就定義生成了，所以在</p>



<pre class="wp-block-code"><code>@import "variables";</code></pre>



<p>之後對 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$theme-colors</mark></code> 的修改，都不會繼承到 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$utilities-colors</mark></code> (它已經生成了)。</p>



<p>而 Bootstrap 5.2 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$utilities-colors</mark></code> 移到 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">_map.scss</mark></code>，整個架構上會比較清楚，你的 Bootstrap CSS build 順序可以參考：</p>



<pre class="wp-block-code"><code>// Functions come first
@import "functions";

// Your optional variable overrides here

// Variables come next
@import "variables";

// Your optional Sass map overrides here

// Third the default maps
@import "maps";

// The rest
@import "mixins";
@import "utilities";
@import "root";
@import "reboot";</code></pre>



<h2 class="wp-block-heading">新的 CSS helpers and utilities</h2>



<p>新的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.text-bg-{color}</mark></code> helper，使用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.text-bg-{color}</mark></code> 可以直接設定 background-color 和文字顏色，而不是兩個 css class 個別設定。</p>



<p>font-weight 方面新增 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.fw-semibold</mark></code> (font weight 600)。border-radius 方面新增 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.rounded-4</mark></code> (border radius 1rem) <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.rounded-5</mark></code> (border radius 2rem)</p>



<h2 class="wp-block-heading">Responsive offcanvas</h2>



<p>Bootstrap 5.2 可以使用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.offcanvas-{sm|md|lg|xl|xxl}</mark></code>，例如 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.offcanvas-lg</mark></code>，在 viewport 大於 lg breakpoint 時，已經顯示的 offcanvas 會隱藏。</p>



<p>Bootstrap 5.0、5.1 就開始使用的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.offcanvas</mark></code> class 仍然存在，使用 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.offcanvas</mark></code> 顯示就不隨 viewport 大小而改變。</p>



<h2 class="wp-block-heading">compile CSS Grid 版本時可以包含 container class</h2>



<p><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">scss/_variables.scss</mark></code> 新增了一個變數 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">$enable-container-classes</mark></code>，如果是 true，當 compile 成 CSS Grid 版本，container class 仍然會 compile 進去 (5.1 之前不會)。</p>



<h2 class="wp-block-heading">總結</h2>



<p>Bootstrap 5.2 沒有大的架構更新，就是多了一些 CSS helper class。CSS 變數的使用幾乎遍及所有元件，所以大家要知道 CSS 變數的使用是一個趨勢。也要稍微知道一下新的 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">_maps.scss</mark></code>，它的邏輯是什麼，Bootstrap 5.2 CSS build 的順序是什麼。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>從 Compat 2021 到 Interop 2022，史上第一次所有的主流瀏覽器，合作解決相容性的問題</title>
		<link>https://blog.yuyansoftware.com.tw/2022/04/compat-2021-interop-2022-browser-compatibility/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Mon, 18 Apr 2022 03:50:14 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[網路科技]]></category>
		<category><![CDATA[Link5]]></category>
		<category><![CDATA[競合策略]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=10239</guid>

					<description><![CDATA[史上第一次所有主流的瀏覽器廠商 (包含 Google Chrome, Apple Safari, Microsoft Edge, Mozilla Firefox) 聯合起來，一起解決瀏覽器相容性的問題，一起成立了一個 Interop 2022 專案。]]></description>
										<content:encoded><![CDATA[
<p><a rel="noreferrer noopener" href="https://web.dev/interop-2022/" target="_blank">https://web.dev/interop-2022/</a><br>前幾天看到這篇文章，史上第一次所有主流的瀏覽器廠商 (包含 Google Chrome, Apple Safari, Microsoft Edge, Mozilla Firefox) 聯合起來，一起解決瀏覽器相容性的問題。因此這幾家瀏覽器廠商一起成立了一個 Interop 2022 專案。</p>



<p>上方 web dev 文章提到了 compatibility, interoperability 這兩個字的不同。</p>



<p><strong>compatibility</strong> 指的是 &#8220;site compat&#8221;，應該是以網站為主，同一網站在不同的環境應該要有類似的行為。<strong>interoperability</strong> 應該是以環境為主，在這裡指的是瀏覽器，不同的瀏覽器對一樣的語法、指令，應該要有高度類似的行為。</p>



<p>因為 compatibility, interoperability 這兩個字嚴格來講語意不太相同，這幾家瀏覽器廠商是選用 interoperability 的 <strong>Interop</strong>。</p>



<p><a rel="noreferrer noopener" href="https://web.dev/compat2021/" target="_blank">https://web.dev/compat2021/</a><br>事實上從 2019，Google, Mozilla, Microsoft 就已經合作開始在研究瀏覽器相容的議題，並在 2021 成立了 <strong>Compat 2021</strong> 專案。Compat 2021 專案專注於以下五個領域：</p>



<ol class="wp-block-list">
<li>CSS Flexbox</li>



<li>CSS Grid</li>



<li>position: sticky</li>



<li>aspect-ratio</li>



<li>CSS Transforms：有 3D transform 和動畫時，每個瀏覽器行為有可能不同。</li>
</ol>



<p>Compat 2021 對新 CSS 語法的普及，不同瀏覽器相容性的提升，都有一些明顯的成果。</p>



<p>這邊聊一下<strong>微軟</strong> (Microsoft)，注意 <strong>Compat 2021</strong> 的成員已經有微軟了，他們已經跟 Google, Mozilla 合作很久了。現任的微軟領導班子真的很厲害，解開了傳統賣套裝軟體 (Windows, Office) 的束縛。走向雲端訂閱制，走向行動裝置，軟體也同時在 Android, iPhone, Mac 上架。</p>



<p>瀏覽器方面打掉 IE，用 Chromium 當核心重做 Edge。用 Chromium 當核心就代表要跟 Google 合作，微軟想得也很清楚，就是跟 Google 合作。</p>



<p>撰文的現在是2022年4月，瀏覽器市佔率 Edge 已經接近第二名的 Safari，很多3C網站都預測 Edge 市佔率將會超越 Safari。<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">微軟現任的領導班子很厲害，公司策略都想得很清楚，也是商業競合策略的最佳教材。</mark></p>



<p><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">公司業務的某個部分跟外部合作，一定會有妥協的部分，但可能因此會有很多機會、很多成長，那為什麼不合作。</mark></p>



<p>不管是微軟，還是其他巨頭企業，當然都知道<strong>競合策略</strong>，當然也知道<strong>賽局理論</strong>，這次 Interop 2022 的合作就是最好的例子。延伸閱讀：<a rel="noreferrer noopener" href="https://blog.yuyansoftware.com.tw/2022/03/the-art-of-strategy-dixit-nalebuff/" target="_blank">[讀書筆記] 思辨賽局 (The Art of Strategy)</a></p>



<p>回到 <strong>Interop 2022</strong>，它主要專注在以下 15 個領域：</p>



<ol class="wp-block-list">
<li>Cascade Layers<br>關於這個主題我有一篇文章：<a href="https://blog.yuyansoftware.com.tw/2022/02/css-cascade-layers-specificity/" target="_blank" rel="noreferrer noopener">CSS Cascade Layers (@layer)，解決長期以來 CSS 競爭權重 (Specificity) 的問題</a></li>



<li>Color Spaces and Functions</li>



<li>Containment</li>



<li>Dialog Element</li>



<li>Forms</li>



<li>Scrolling</li>



<li>Subgrid</li>



<li>Typography and Encodings</li>



<li>Viewport Units：<strong>CSS Values and Units Module Level 4</strong> 新定義了 3 個單位，lvh, svh, dvh</li>



<li>Web Compat：以使用者的角度來講，同一網站不同瀏覽器，有沒有真的會影響到使用體驗的部分。<br><mark style="background-color:rgba(0, 0, 0, 0);color:#999999" class="has-inline-color">=== 以下是從 Compat 2021 繼承下來 ===</mark></li>



<li>CSS Flexbox</li>



<li>CSS Grid</li>



<li>position: sticky</li>



<li>aspect-ratio</li>



<li>CSS Transforms</li>
</ol>



<p>Chrome, Safari, Edge, Firefox 在 <strong>Interop 2022</strong> 規格所得的分數，會持續在這個網頁更新 <a rel="noreferrer noopener" href="https://wpt.fyi/interop-2022" target="_blank">https://wpt.fyi/interop-2022</a></p>



<h4 class="wp-block-heading">結論</h4>



<p>撰文的現在是2022年4月，CSS 從 responsive design, Flexbox, CSS Grid 等新技術到現在，已經十幾年的時間。以整個軟體工程來講，CSS 是年輕的語言沒錯，但十幾年下來，要找到新的突破點、優化點確實也不容易。</p>



<p>但畢竟任何網路應用，離不開網頁的呈現。幾個大的網路巨頭企業，也各自有自己的瀏覽器。但值得高興的是，這幾家巨頭企業在瀏覽器的部分是傾向於合作，而不是對抗。巨頭的合作對 CSS 這個語言，網路科技的發展，乃至於整個網路環境，都是一個比較好的發展方向。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>CSS Cascade Layers (@layer)，解決長期以來 CSS 競爭權重 (Specificity) 的問題</title>
		<link>https://blog.yuyansoftware.com.tw/2022/02/css-cascade-layers-specificity/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Sun, 06 Feb 2022 05:18:46 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[Link5]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=9625</guid>

					<description><![CDATA[稍微有點規模的專案，都有著複雜的 HTML 結構。你在開發某一頁時，根本不會知道你寫的這一個 CSS，跟已存在的 CSS 到底誰的權重重。如果已存在的 CSS 權重重，就暴力覆寫，大概會是這樣的情況。]]></description>
										<content:encoded><![CDATA[
<p>前幾天看到一篇文章<br><a href="https://developer.chrome.com/blog/cascade-layers/" target="_blank" rel="noreferrer noopener">https://developer.chrome.com/blog/cascade-layers/</a></p>



<p>Chromium 99、Firefox 97、Safari 15.4 將會支援 CSS Cascade Layers。雖然全瀏覽器的支援度還是不夠，但這幾家瀏覽器的大廠支援，就說明了 Cascade Layers 會成為未來的規格。</p>



<p>Cascade Layers 的官方文件在這裡<br><a href="https://www.w3.org/TR/css-cascade-5/#layering" target="_blank" rel="noreferrer noopener">https://www.w3.org/TR/css-cascade-5/#layering</a></p>



<p>上面文件是 CSS Cascading and Inheritance Level 5，此份文件從 Level 3 到撰文的此時 (2022年2月) 已經出到 Level 6。CSS Cascading and Inheritance 就是負責定義在多個 CSS 語法下，一個 HTML element，最終是採用哪一個 CSS。</p>



<p>CSS Cascade 中很重要的一件事，就是搞清楚 Specificity (權重) 的概念。一般來講，用 HTML ID 來指定 CSS 的權重會大於用 CSS class，用 CSS class 來指定 CSS 的權重又大於用 HTML tag。</p>



<p>前幾年有人提出 BEM (Block Element Modifier) 命名的概念，它就是依照 HTML 區塊、區塊裡的元素、modifier 等，把所有名稱連起來，寫一個長長的 CSS selector。經驗夠的工程師就知道，這樣多難維護啊。重點是專案要快速完成吧，而不是把團隊的精力時間花在維護 BEM 命名。</p>



<p>稍微有點規模的專案，都有著複雜的 HTML 結構。你在開發某一頁時，根本不會知道你寫的這一個 CSS，跟已存在的 CSS 到底誰的權重重。如果已存在的 CSS 權重重，就暴力覆寫，大概會是這樣的情況。一整個專案的 CSS 有點像是在同一個平面，沒有任何結構，彼此競爭。</p>



<p>新的規格 Cascade Layers 試圖解決這個問題。<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">以優先級來講，永遠先考慮 Cascade Layers，再考慮 Specificity (權重)。</mark></p>



<p>我們來看一段 sample code</p>



<pre class="wp-block-code"><code>@layer base {
  div.abc {
    color: red;
  }
}

@layer theme {
  div {
    color: green;
  }
}</code></pre>



<p>如果現在 HTML 裡有一個 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">&lt;div class="abc"&gt;</mark></code>，裡面的字是什麼顏色？以權重來講，有指定 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">.abc</mark></code> 當然權重比較高。但是因為有使用 @layer，後宣告的 @layer 永遠覆寫之前宣告的 @layer，所以 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">&lt;div class="abc"&gt;</mark></code> 裡面的字是綠色。</p>



<p>在 CSS 檔案最上方，可以明確指定 layer 順序，例如加這一行到 CSS 檔案最上方</p>



<pre class="wp-block-code"><code>@layer theme, base; // 明確指定先 theme 再 base</code></pre>



<p>這樣 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@layer base</mark></code> 裡指定的 CSS 就會覆寫 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@layer theme</mark></code> 裡指定的 CSS。</p>



<p>如同名稱 Cascade Layers，它把本來在同一個平面，互相競爭(權重)的 CSS，上下分層了。當然一般狀況，先宣告 base layer (下層)，再宣告 theme layer (上層)，甚至客製的元件 layer (更上層)。</p>



<p>上方 Chrome Developer 的文章有提醒</p>



<ol class="wp-block-list"><li>在 @layer 中的 CSS selector 仍然要寫全稱。本來寫什麼，在 @layer 裡就寫什麼，不要誤解 @layer 可以讓你的 CSS 少寫什麼。</li><li>如果同時有 layered / non-layered CSS，non-layered CSS 永遠先被採用，不管它的 selector 權重如何。所以要導入 Cascade Layers，先從基底的 CSS 開始導入，才不會影響整個專案。</li><li>!important 會反轉優先順序。承第二點，如果同時有 layered / non-layered CSS，而且同時有 !important，<code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@layer !important</mark></code> 的優先級高。<br>如果同時有多個 layered CSS，而且同時有 !important，第一個 layered CSS with !important 的優先級最高。<br><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">不管是 layered / non-layered 比較，多個 layer 比較，!important 都反轉了優先順序。</mark></li><li>@layer 的語法是宣告新的 layer。例如一 layer abc，如果你 <br><code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@import '....' layer(abc);</mark></code> <br>之後再宣告 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@layer abc</mark></code>，這個 <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">@layer abc</mark></code> 無效。不會有任何權重，是完全被忽略。<br>總之，Chrome Developer 的文章建議，CSS 檔案一開始就宣告 @layer，另一方面也明確的指定 layer order。</li></ol>



<h4 class="wp-block-heading" id="結論">結論</h4>



<p>Chromium 99、Firefox 97、Safari 15.4 將會支援 CSS Cascade Layers，這幾家瀏覽器的大廠支援，說明了 Cascade Layers 會成為未來的規格。</p>



<p>本篇文章走了一遍 CSS Specificity (權重)，但長期以來全部 CSS 在同一平面競爭權重，有總是暴力覆寫的問題。Cascade Layers 可以將整個專案的 CSS 結構化，由下到上分為 base, theme, components 等，是一個合理又聰明的做法。上方圖層 (layer) 覆蓋下方圖層，也是一個清楚而直覺的想像。</p>



<p>Cascade Layers 可能會成為未來的規格，值得投資時間，有在做前端的讀者可以參考看看囉。</p>



<p>延伸閱讀：<a href="https://blog.yuyansoftware.com.tw/2022/04/compat-2021-interop-2022-browser-compatibility/" target="_blank" rel="noreferrer noopener">從 Compat 2021 到 Interop 2022，史上第一次所有主流的瀏覽器廠商，合作解決瀏覽器相容性的問題</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Bootstrap 5.1 主要更新：開始使用 CSS Grid 實作 grid system，新的元件，更多的 CSS 變數 (custom property)</title>
		<link>https://blog.yuyansoftware.com.tw/2021/08/bootstrap-5-1-css-grid-custom-property/</link>
		
		<dc:creator><![CDATA[Larry]]></dc:creator>
		<pubDate>Tue, 24 Aug 2021 07:46:34 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[前端工程]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<guid isPermaLink="false">https://blog.yuyansoftware.com.tw/?p=8377</guid>

					<description><![CDATA[很多專家認為 CSS Grid 是繼 Flexbox 後，近代 CSS 的另一個里程碑。Bootstrap 4 開始使用 Flexbox 實作 grid system，Bootstrap 5.1 開始可以切換為 CSS Grid 實作。]]></description>
										<content:encoded><![CDATA[
<p>圖片來源 <a href="https://blog.getbootstrap.com/2020/06/16/bootstrap-5-alpha/" target="_blank" rel="noreferrer noopener nofollow">Bootstrap官方部落格</a></p>



<p><a href="https://blog.getbootstrap.com/2021/08/04/bootstrap-5-1-0/" target="_blank" rel="noreferrer noopener nofollow">https://blog.getbootstrap.com/2021/08/04/bootstrap-5-1-0/</a><br>前幾天 (2021年 8/4) Bootstrap 5.1 釋出了。每次看到新的 Bootstrap 版本釋出，都會有感於時間過的真的飛快。</p>



<p>上一篇我關於 Bootstrap 5 的<a href="https://blog.yuyansoftware.com.tw/2020/12/bootstrap-5-features/">文章</a>是在去年底 (2020年底)，一轉眼 2021 年大半年又過了。</p>



<p>以下是 Bootstrap 5.1 的主要更新：</p>



<h2 class="wp-block-heading" id="使用-css-grid-實作-grid-system">使用 CSS Grid 實作 grid system</h2>



<p>使用 CSS Grid 實作 grid system 是 <meta charset="utf-8">Bootstrap 5.1 的主要更新。很多專家認為 CSS Grid 是繼 Flexbox 後，近代 CSS 的另一個里程碑。Bootstrap 4 開始使用 Flexbox 實作 grid system，<meta charset="utf-8">Bootstrap 5.1 預設也是 Flexbox <meta charset="utf-8">實作，但可以切換為 CSS Grid 實作。</p>



<p>同時也釋出了新的 CSS Grid 文件，5.0 還沒有這頁文件，從 5.1 開始。<br><a rel="noreferrer noopener" href="https://getbootstrap.com/docs/5.1/layout/css-grid/" target="_blank">https://getbootstrap.com/docs/5.1/layout/css-grid/</a></p>



<p>Bootstrap 5.1 如何切換 Flexbox 實作到 CSS Grid 實作？找到檔案位置 <code><span class="has-inline-color has-vivid-cyan-blue-color">/bootstrap-5.1.0/scss/_variables.scss</span></code><span class="has-inline-color has-black-color">, 設定</span>這兩個變數</p>



<pre class="wp-block-code"><code>$enable-grid-classes: false; 
$enable-cssgrid: true;</code></pre>



<p>改好了重新 compile SCSS。Bootstrap 5.0 的 <code><span class="has-inline-color has-vivid-cyan-blue-color">_variables.scss</span></code> 沒有 <code><span class="has-inline-color has-vivid-cyan-blue-color">$enable-cssgrid</span></code> <meta charset="utf-8">這個變數，所以可以確定是 5.1 引入的。</p>



<p>一樣是 Bootstrap Grid System row/col 的架構，只是將 row 換成 grid，col 換成 g-col。例如這樣三個 div 分別在 12 份中佔有一份、兩份、和三份。<br><code><span class="has-inline-color has-vivid-cyan-blue-color">.grid</span></code> 設定 <code><span class="has-inline-color has-vivid-cyan-blue-color">display:grid</span></code>，<code><span class="has-inline-color has-vivid-cyan-blue-color">g-col-*</span></code> 設定 <code><span class="has-inline-color has-vivid-cyan-blue-color">grid-column</span></code></p>



<pre class="wp-block-code"><code>&lt;div class="grid"&gt;
  &lt;div class="g-col-1"&gt;
    Column
  &lt;/div&gt;
  &lt;div class="g-col-2"&gt;
    Column
  &lt;/div&gt;
  &lt;div class="g-col-3"&gt;
    Column
  &lt;/div&gt;
&lt;/div&gt;</code></pre>



<p><code><span class="has-inline-color has-vivid-cyan-blue-color">.grid</span></code> 同時定義了 CSS gap。相較於用 padding/margin 去做 gutter，gap 是新一代做 gutter 的方式。如果仔細去看，每個 g-col 本身沒有 padding/margin，但卻能彼此分開，這不符合 CSS box model 阿？larry 看到一種說法，gutter 如字面翻譯是水溝，在 CSS Grid 裡面 gutter 本身就是一種物件，會佔面積。而 gap 只是定義了 gutter 的寬度。</p>



<p>下方是 Bootstrap CSS Grid 文件中的 sample code。這個 sample 做了一個 9&#215;9 的 grid，第一個 child 是第一行第一個，第二個 child 是第二行第二個，第三個 child 是第三行第三個。以賓果遊戲來說，是左上到右下連線的圖形。</p>



<pre class="wp-block-code"><code>&lt;div class="grid" style="--bs-rows: 3; --bs-columns: 3;"&gt;
  &lt;div&gt;Auto-column&lt;/div&gt;
  &lt;div class="g-start-2" style="grid-row: 2"&gt;Auto-column&lt;/div&gt;
  &lt;div class="g-start-3" style="grid-row: 3"&gt;Auto-column&lt;/div&gt;
&lt;/div&gt; </code></pre>



<p>從這個 sample 我們可以看出</p>



<ol class="wp-block-list">
<li>Bootstrap 官方鼓勵 inline CSS custom property 的使用。inline 指定 <code><span class="has-inline-color has-vivid-cyan-blue-color">--bs-rows</span></code>, <code><span class="has-inline-color has-vivid-cyan-blue-color">--bs-columns</span></code> 是不是更靈活，redundant code 更少一些。</li>



<li><code><span class="has-inline-color has-vivid-cyan-blue-color">g-start-*</span></code> 可以指定水平開頭的位置，inline CSS <code><span class="has-inline-color has-vivid-cyan-blue-color">grid-row</span></code> 可以指定是屬於第幾行。</li>
</ol>



<h2 class="wp-block-heading" id="offcanvas-in-navbar-new-component">Offcanvas in navbar (new component)</h2>



<p>Offcanvas 在 Bootstrap 5.0 已經新增了，是一個新的元件。觸發時左、右、上、下其中一側彈出視窗，按按鈕或按叉結束時再縮回原處。</p>



<p>Bootstrap 5.1 將 Offcanvas 和 navbar 做整合。尤其手機版的 navbar 通常會縮成一個 toggle button，點了之後可以指定 Offcanvas 從哪個方向彈出，navbar 的內容可以放在 Offcanvas 裡面。</p>



<h2 class="wp-block-heading" id="placeholder-new-component">Placeholder (new component)</h2>



<p>將還沒 load 好的文字，用銀色區塊替代。例如 Facebook，早就是這樣做 placeholder。</p>



<p>在要顯示銀色區塊的 DOM (不一定是銀色，可以自行設定 <code><span class="has-inline-color has-vivid-cyan-blue-color">background-color</span></code>)，加上 CSS class <code><span class="has-inline-color has-vivid-cyan-blue-color">.placeholder</span></code>，DOM 的寬度要設定一下。container 可以加上 CSS class <code><span class="has-inline-color has-vivid-cyan-blue-color">.placeholder-glow</span></code> 或 <code><span class="has-inline-color has-vivid-cyan-blue-color">.placeholder-wave</span></code>，讓 placeholder 區塊有小小的水波閃爍。</p>



<h2 class="wp-block-heading" id="bg-text-utility-的實作變數化">.bg-* &amp; .text-* utility 的實作變數化</h2>



<p>Bootstrap 5.0 中 background color utility 實作如下 (text color utility 類似，僅用 background 舉例)</p>



<pre class="wp-block-code"><code>.bg-success {
  background-color: #198754 !important;
}</code></pre>



<p>Bootstrap 5.1 改為</p>



<pre class="wp-block-code"><code>.bg-success {
  --bs-bg-opacity: 1;
  background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important;
}</code></pre>



<p>這樣如果你要微調 <code><span class="has-inline-color has-vivid-cyan-blue-color">.bg-success</span></code> 的顏色，在你的專案裡重新設定 <code><span class="has-inline-color has-vivid-cyan-blue-color">--bs-success-rgb</span></code> 就好了。未來 Bootstrap 會接著把其他 utility 也變數化。Bootstrap 的演進<meta charset="utf-8">有這樣的味道：<meta charset="utf-8">Bootstrap 只管架構，顏色等屬性由 CSS 變數設定。對軟體工程有研究的讀者應該知道，資料 / 邏輯分離的概念。</p>



<h2 class="wp-block-heading" id="結論">總結</h2>



<p>Bootstrap 5.1 開始使用 CSS Grid 實作 grid system，而且又新增了很多元件。從 Bootstrap 的發展和文件可以看出來，Bootstrap 非常大量的使用 CSS custom property，同時也鼓勵開發者在專案裡使用 CSS custom property 做出變化。CSS Grid、Bootstrap 的新元件、CSS custom property 的使用，都是很值得參考的。</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
