顯示具有 css 標籤的文章。 顯示所有文章
顯示具有 css 標籤的文章。 顯示所有文章

2026年2月5日 星期四

動態單位dvh, svh, lvh

我知道我孤陋寡聞,這東西都出來多久了,現在才在追,沒錯,要不是瀏覽器遇到奇怪的問題,我大概一被子也不會碰到這東西,原本以為傳統vh, %已經夠用了,沒想到有推出這麼好用的東西,廢話不多說,直接開始

1. svh (Small Viewport Height)

  • 含義小視窗高度

  • 定義:當瀏覽器的 工具列完全顯示(展開狀態)時,所剩餘的可視區域高度。

  • 特性:它是三者中最小的高度。

  • 場景:當你希望元件在任何情況下都不會被工具列遮擋時使用。

2. lvh (Large Viewport Height)

  • 含義大視窗高度

  • 定義:當瀏覽器的 工具列完全隱藏(收起狀態)時,所能達到的最大可視區域高度。

  • 特性:它的數值與傳統的 100vh 基本一致,但在某些裝置上更穩定。

  • 場景:當你追求極致的全螢幕視覺效果,且不介意底部內容暫時被工具列覆蓋時使用。

3. dvh (Dynamic Viewport Height)

  • 含義動態視窗高度

  • 定義:根據 工具列目前的顯示狀態自動調整 的高度。

  • 特性:當工具列縮小時,100dvh 會變大;當工具列展開時,它會縮小。

  • 場景:這是目前最推薦的單位,適合用來製作「真正的全螢幕」滿版背景或中間定位的彈窗(Modal),它能確保元件始終在當前的畫面中央。


快速對比表

單位全寫工具列狀態高度大小適用情況
svhSmall Viewport Height展開 (Max UI)最小確保內容不被遮擋
lvhLarge Viewport Height隱藏 (Min UI)最大追求最大視覺空間
dvhDynamic Viewport Height自動變動隨動最推薦,自動適應當前畫面
那100dvh跟100%差別在哪呢,主要就是不會受到父元素影響吧,上圖表
特性height: 100%height: 100dvh
參照對象父元素 的高度。視窗 (Viewport) 的動態高度。
依賴性必須「層層向上」定義高度。獨立存在,不論父元素高度為何。
動態縮放隨父元素變動。隨瀏覽器工具列(網址列)縮放變動。
預設行為若父元素沒設高度,此設定無效。即使放在深層結構,也能直接抓到螢幕高度。
所以傳統做法需要先定意html, body的高度,讓container可以做到高度100%
html, body, .container {
    height: 100%;
}
之後就不用這麼麻煩了,直接
.container {
    height: 100dvh;
}
搞定收工,歡呼聲!

2025年4月28日 星期一

placeholder突然變粗了?css踩坑系列

事情是這樣的,在案發當天晚上十點左右,UI突然敲我說為什麼input所有placeholder字體都變粗了,我到底改了什麼,叫我退版。

問題是我根本什麼也沒改,被UI被PM被測試追殺已經很煩了誰還有空亂加東西,我矢口否認,但UI開始瘋狂跳針叫我退版,我一氣之下回他:「小姐你知道我今天上了多少版嗎?你要我退版好歹也要讓我知道哪一版啊!」

然後我就被吉了!

但這不是今天重點,總之後來我使用下面這語法暫時瞞過主管趕上線

input::placeholder {
@apply font-light;
}



硬把字體調細了。然後我仔細去看UI給我的對比,確實這頁的placeholder比較粗....這就神奇了。但礙於當時已經很晚了,趕快做完保命要緊!

然後就過了兩週,今天心血來潮想要一探究竟,最終發現最外的.page裡面有個語法

-webkit-font-smoothing: antialiased;

把這語法點掉就變粗了,但因為這在很外層所以當天沒找到,礙於時間壓力也沒心思慢慢看。

但為什麼這頁會出事呢?根據css說法這語法是用來消除鋸齒,讓文字更平滑,看起來也會更細,

那為什麼這頁會突然變粗呢,原因是因為頁面中底部的popup我是使用React.createPortal去創建在body下面的,所以他根本沒吃到.page的css

所以UI口中的突然壞掉要我退版,就是我手刻了這個popup導致的,但~鬼會知道啊~

唉~總之~又是個美好的一天~


補充:

事後在另外一個專案又發生類似的事情,結果不是出在這css,查詢結果問題發生在字體...好一個博大精深


2024年1月16日 星期二

如何再遮罩上挖個洞

前言

相信大家都有用過Modal,都有遇過背後那半透明的遮照,但如果要做到以下效果,在下方按鈕上挖一個洞,我的第一直覺應該會用圖片去做處理


實際上這是我接手同事專案後他做出來的效果,我仔細研究了一下他的程式碼,發現想法還挺有趣的直得學習一下。
因為這部分程式碼不好呈現,所以今天就用截圖代替吧,絕對不是因為我比較懶


簡單解釋,mask-info一樣左上對齊,設成fixed。
這裡使用
const { x, y, height, width } = element.getBoundingClientRect()
去取得按鈕(目標元素)的座標及大小,放到類元素:before去瞄準絕對位置跟尺寸,最後使用box-shadow讓陰影往外延伸並且設上透明度(照片中往外延伸3000px,以手機版來說也很夠用了)。
打完收工。

後記
跟以往我總是從座標0,0開始思考有點不一樣,沒想到類元素還可以這樣使用。只能說世界還是很大啊~(煙

<div class="mask-info" :style="clipPath">
...
</div>
const clipPath = computed(() => {
const { x, y, height, width } = props.data // element.getBoundingClientRect() 進來的值
return {
"--top": `${y}px`,
"--left": `${x}px`,
"--width": `${width}px`,
"--height": `${height}px`,
}
})
.mask-info {
@apply fixed left-0 right-0 top-0 bottom-0 z-[100];

&:before {
@apply absolute block rounded;
content: "";
left: var(--left);
top: var(--top);
width: var(--width);
height: var(--height);
box-shadow: 0 0 0 3000px rgba(0, 0, 0, 0.8);
}
}

另外紀錄一個點,同事使用var(--left)去取得主元素的style left值,這點也挺特別的,沒有使用vue3原生的v-bind去取
如果沒意外應該會寫成這樣
left: v-bind("clipPath['--left']")


2023年7月14日 星期五

100%與100vh的差異

除了網路上大家常說有沒有內容,會不會被撐開的差異外,今天在實際操作上還真的遇到一點差異,而平常不會注意到的

這張就是我把高度設為100vh的狀況,container是用flex完全置中,但上面卻會有一塊空白,導致確定按鈕會有點超出介面

這張就是我高度設定100%,在完全置中情況下,上下空白幾乎是一樣的

為什麼會有這樣些微的差距是因為vh是表示螢幕的高度,而非扣除掉原生軟體介面,剩餘的高度,所以第一張圖來看,如果把網址列及控制列算進去,他確實是完全置中沒錯,但這不是我們要的效果,所以乖乖設成100%吧



2021年1月7日 星期四

改變Vue sub component樣式

相信元件帶給大家的好處不言而喻,但使用上總是有一些不方便之處,例如三方的元件樣式我能否調成自己喜歡的?我自己的元件在不同情境下樣式能否不一樣?難道最終都難逃考比爬斯特,重新寫一個的命運嗎?

小編的任務就是盡可能幫各位提早下班,第一個問題,我們可以寫個全域css去改變他

先假設我們的子元件長這樣

// hello.vue
<div class="component-hello">
  hello
</div>
<style scoped>
  .component-hello {
    colorred
  }
</style>

父元件長這樣

// App.vue
<div class="app">
  <hello />
</div>

<style>
  .app .component-hello {
    colorblue
  }
</style>

在先不考慮css分數的情況下,這樣寫原則上就可以覆蓋component裡面的樣式。

雖然一般三方class寫都得不錯,不太會有重複的情況,但css汙染在我心目中跟watch一樣危險,有很多不可控的因素,所謂的不可控,所謂的黑魔法,就是當下可能會覺得很爽,一個禮拜之後就會變成導致你加班的原因,且一個不小心就會演變成泥沼戰(就是比誰宣告比較兇),所以能不要互相汙染、互相傷害就不要去做這種事,能寫sooped就給他用力寫,為這社會帶來一絲和諧吧!

然而你會發現當你加上了scoped,你原本吃的到css一夕之間的突然都吃不到了,原因是因為scoped會為該component的所有tag注入一個唯一的屬性(亂數產生),但卻不會為子component注入該屬性,所以導致子component吃不到上層scoped的css。那這問題怎麼要解呢?

這就是今天寫這篇主題的目的:那就是使用v-deep,用法很簡單如下。

// App.vue
<div class="app">
  <hello />
</div>

<style scoped>
  .app /deep/ .component-hello {
    colorblue
  }
</style>

這樣就可以控制在App.vue下的component-hello顏色才會是藍色,這樣也同時解決了我們上述的第二個問題,同一個元件在不同class下可以有不同樣式就是這樣來的。

大部分語言也可以簡寫成如下,我以stylus為例

<style lang="stylus" scoped>
  .app >>> .component-hello 
    color blue
</style>

scss或sass語言也可以簡寫成如下

<style lang="stylus" scoped>
  .app ::deep .component-hello 
    color blue
</style>

打完收工下班!

2016年12月8日 星期四

如何只靠html&css輸出A4的畫面

目標

相信大家在做專案的時候不免會遇到一些要輸出報表,或輸出什麼單什麼單的時候。

然而通常我們用的技術越簡單,對專案開發速度的提升跟交接的難易度也越低。

而這個方法,真的是小編所能找到最簡單的方法了,過程中只有 Html 跟 CSS ,甚至一行 JS 都不需要有!(範例中那行是方便大家輸出跟觀察,直接把print指令寫好了)這對目前是前端工程師的小編來說,根本是逆天的簡單(當然對各位大大來說也是一樣啦 ),而唯一要做的前置作業,就是去查出你要輸出的紙張的size,必要時再去弄一張版型的圖片,當然圖片大小也要調得一樣,這樣可以方便做細部的調整。

廢話不多說我們就直接開始吧。

Html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
 <title>JS Bin</title>
</head>
<body>
<div class="book" id="app">
    <div class="page">
        <div class="subpage">
          page1/2
      </div>  
    </div>
    <div class="page">
        <div class="subpage">
          page2/2
      </div>  
    </div>
</div>
</body>
<sciript>widnow.print()</script>
</html>

上網查了一下,A4 size =  210mm*297mm,那我們就開始寫CSS吧

CSS:

    body {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        background-color: #FAFAFA;
        font: 12pt "Tahoma";
    }
    * {
        box-sizing: border-box;
        -moz-box-sizing: border-box;
    }
    .page {
        width: 210mm; /*隨著紙張大小異動*/
        min-height: 297mm;/*隨著紙張大小異動*/
        padding: 20mm;
        margin: 10mm auto;
        border: 1px #D3D3D3 solid;
        border-radius: 5px;
        background: white;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
    }
    .subpage {
        padding: 1cm;
        border: 5px red solid;
        height: 257mm;/*隨著紙張大小異動*/
        outline: 2cm #FFEAEA solid;
    }
 
    @page {
        size: A4;
        margin: 0;
    }
    @media print {
        html, body {
            width: 210mm;/*隨著紙張大小異動*/
            height: 297mm; /*隨著紙張大小異動*/
        }
        .page {
            margin: 0;
            border: initial;
            border-radius: initial;
            width: initial;
            min-height: initial;
            box-shadow: initial;
            background: initial;
            page-break-after: always;
        }
    }


小結

如果有需要,可以直接在page裡面加入 background-image,自行加入要列印單子的版型,這樣可以快速調整到自己想要的位置,甚至可以儲 positon 到資料庫,因應各家不同廠商的單子。光想到就內牛滿面。

小編過足了兩年都過著用 position:releative 去微調每個欄位,然後再列印出來,看到底還差多少,然後硬體不同還會跑版,一整個吐血,無形中不知道浪費了多少紙張,讓北極熊唾棄了幾次,所以後來小編終於受不了良心譴責,離開了那間公司,哈。

不過就這樣短短的程式碼,確實簡單又便利。留起來筆記,也希望可以幫助正在為報表所苦的朋友們,也歡迎大家留言或寄信給我討論