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

2024年4月13日 星期六

自製表單欄位的浮動標題/標籤 (Floating Field Label/Title)

今天有個需求是想要製作一個
"表單欄位的浮動標題/標籤 (Floating Field Label/Title)",
用自己的想法自製完了以後在這篇文中做個紀錄和分享一下。

Floating Field Label/Title 具體是什麼可以參考 Bootstrap 的一個實現:Floating labels
就是一個被設計放在表單欄位 (例如 <input type="text"/>) 中的 Placeholder,
但當要在欄位上輸入內容時,這個 Floating Field Label 會自行地往上移動讓出欄位的空間給
使用者輸入內容。

需求如下:

  1. Floating Label 平常顯示位置在欄位之中。
  2. 欄位必須要能容納 Floating Label 的所有文字,也就是 Floating Label 內容不能被截斷或超出欄位。
  3. 當欄位被處於 focus 狀態 (例如滑鼠點到欄位使其處於擁有焦點狀態) 或
    欄位處於有被輸入了文字 的情況, Floating Label 必須要往上移動讓出欄位空間,
    同時欄位上方必須要能自動根據 Floating Label 的文字多少預留足夠 Floating Label 上移的空間。

首先先直接看最後的成品,再來對其說明:

HTML:

<div>
  <div class="hidden-text">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.
  </div>
  <div class="wrapper">
    <div>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.
    </div>
    <input type="text" placeholder="" />
    <label>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.
    </label>
  </div>
</div>

CSS:

:root {
  --wrapper-width: 300px;
}

.hidden-text {
  visibility: hidden;
  width: var(--wrapper-width);
}

.wrapper {
  position: relative;
  width: var(--wrapper-width);
}

label {
  position: absolute;
  top: 0px;
  pointer-events: none;
  transition: all 0.25s ease;
}

input:not(:placeholder-shown) + label,
input:focus + label{
  top: -100%; /* 這是根據父節點的高度設定 top */
  /* transform: translateY(-100%); */ /* 也可以用這個,這是根據自身的高度設定 translateY ,可以用在  框高度是自定義而非由 placeholder 內容決定時使用 */
  transition: all 0.25s ease;
}

input {
    width: var(--wrapper-width);
    height: 100%;
    position: absolute;
    top: 0px;
}

input::placeholder {
  opacity: 0;
}

說明:
HTML 中是我們主要的設計結構,下面這一串文字是用來展示的 Floating Label 測示文字,只是一個 Lorem ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.

注意到在 HTML 上我們的三個 Lorem ipsum 內容是完全一樣的。
然後為了讓各元件的 width 寬度一致,我們在 css 設定了一個 --wrapper-width 變數給各元件共用:

:root {
  --wrapper-width: 300px;
}

想法是這樣的,我們需要一個能夠依照文字內容自行撐高的 <input type="text"/>,
所以我們將它跟一個文字內容放在同一個 wrapper 裡,這裡我們再放了一個 Floating Label 進去,像這樣:

<div class="wrapper">
    <div>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.
    </div>
    <input class="line2" type="text" placeholder=" " />
    <label>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.
    </label>
  </div>

我們利用 <div> 來撐高外層的 .wrapper,然後將 <input> 的高設定成跟 .wrapper 一樣,同時設定  positoin:  absolute; top: 0px; 給 <input> 來讓它可以不影響 .wrapper 的高度。
不要忘了設定 position: relative; 給 .wrapper,這樣 .wrapper 才能做為 <input> position:absolute; top 位置的基準。

注意到 <input> 設定了一個空字串的 placeholder,這是必須的,之後會說明,其是為了能夠被 :placeholder-shown  CSS 選擇器選到。

有一點可以注意到,因為 <input> 在 HTML 是寫在 <div> 之後,所以 <div> 會被 <input> 遮注而不會被看到,這樣我們就不須要特別設定 css 讓 <div> 看不到。

.wrapper {
  position: relative;
  width: var(--wrapper-width);
}

input {
    width: var(--wrapper-width);
    height: 100%;
    position: absolute;
    top: 0px;
}

在看 Floating Label 的 css 之前,我們先看一下最上方的 .hidden-text :

<div class="hidden-text">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ultricies urna nulla, sed viverra purus elementum ut. In hac habitasse platea dictumst. Integer ut dui ligula. Morbi in velit eu urna finibus elementum id consectetur neque.
  </div>

<div> 的作用是讓 .wrapper 上方有一個預留空間可以讓 Floating Label 移上去,所以用文字將其撐高了以後,我們要讓它在保留空間佔位的情況下將字隱藏起來,在這邊用 visibility: hidden 來達到:

.hidden-text {
  visibility: hidden;
  width: var(--wrapper-width);
}

可以注意到,因為上方的 <div> 和下方 .wrapper 用的文字內容一樣,寬度也設定一樣,所以兩者的高度是一樣的。

接下來就是要來設定 Floating Label,首先,Floating Label 跟 <input> 一樣,必須要不撐高 .wrapper 的空間,所以要設定 position: absolute; top: 0px; 。

再來一個比較特別的地方是,因為 Floating Label 的 HTML 寫在 <input> 之後,會擋到 <input> 讓我們無法點擊到 <input>,所以必須要設定 pointer-events: none; 讓點擊能夠穿特過去。

並且我們給它設定一個動畫效果讓它之後在移位時看起來比較滑順,動畫效果不是必須的,不設定也沒關係 :

label {
  position: absolute;
  top: 0px;
  pointer-events: none;
  transition: all 0.25s ease;
}

最後要來設定移位的 css,首先我們希望 <input> 在被 focus 時,Floating Label 能夠移位上去,這可以用 input:focus + label 選擇器來設定,
但如果 <input> 沒有被 focus ,<input> 中有被輸入文字時,我們不希望 Floating Label 被移位回 <input> 裡,這時之前在 <input> 中設定的 placeholder 就派上用場了,
因為 <input> 設定了 placeholder,在 <input> 中有文字被輸入時,placeholder 就會消失看不見,
此時就可以用 :not(:placeholder-shown) 來選擇 placceholder 看不到時的情況。

所以 CSS 就會像是這樣:

input:not(:placeholder-shown) + label,
input:focus + label {
  top: -100%; /* 這是根據父節點的高度設定 top */
  /* transform: translateY(-100%); */ /* 也可以用這個,這是根據自身的高度設定 translateY */
  transition: all 0.25s ease;
}

2023年5月8日 星期一

設計長寬等比例隨視窗大小縮放的 DOM 元素(使用 aspect-ratio 或 padding)

當要設計一個長寬等比例隨視窗大小縮放的 DOM 元素時,
可以使用最新的 CSS 屬性:

aspect-ratio

來達成,
例如現在想要放入一個 Youtube 的 iframe,

<iframe src="https://www.youtube.com/embed/Cu8NnGwYZp0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

寬度要是外層元素的 80%,寬高比要是 16:9,
可以這樣設定:

HTML:

<iframe class="aspect-ratio"  src="https://www.youtube.com/embed/Cu8NnGwYZp0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

CSS:

.aspect-ratio {
  aspect-ratio: 16 / 9;
  width: 80%;
}


不過像在以前還沒有 aspect-ratio 的時代,
有一個蠻常用的、利用了 padding 的特性來實現的方法,
特別在這邊記錄一下。

首先先上 HTML 和 CSS:

HTML:

<div class="wrapper">
  <div class="box">
      <iframe class="box-in" src="https://www.youtube.com/embed/Cu8NnGwYZp0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
  </div>
</div>

CSS:

.wrapper {
  width: 80%;
}

.box {
  width: 100%;
  padding-top: 56.25%;
  height: 0;
  position: relative;
}

.box-in {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
}

接著把上述兩種方法放上在 JsFiddle 的成品來做為比較:

說明:
使用 padding 可以達成等比例 DOM 的原理是,
當元素的 height 是 0 ,並且沒有設定 border 和 margin 等時,
此時示素的高度就由它的 padding-top 或 padding-bottom 決定,
而 padding-top 此時會由它的父元素之寬來做為參考計算,
在上述的例子中,父示素就是 class="wrapper",width 是 80%,在這裡也就是 <body> 寬的 80%,
而 class="box" 設定了 padding-top=56.25%,也就是 9/ 16,
這樣它的高度就會是父元素的寬乘上 9 / 16,然後它的寬會是父元素的寬。

在 class="box" 裡我們還要再設定一個 class="box-in" 元素,
因為 class="box" 有設定 padding-top 的關係,所以位置會被往下推,
要解決這個,我們可以先將 class="box" 設為 position=relative 做為子元素位置 left, top 的參考點,
然後在 class="box-in" 上設定
position=absolute
left = 0
top = 0
來將 class="box-in" 往上放至正確的位置,
接著在 class="box-in" 中就可以放上想要放的 Youtube iframe 了。

2022年12月11日 星期日

CSS display grid 和 flex 對於子元素 width 的差別

 CSS 的 display grid 和 flex 對於子元素的 width 行為不太一樣,
主要差別是:

Grid:
先以父元素的寬度計算子元素均分後的寬度,子元素各自再用 width 屬性計算出自己最後的寬度,width 是百分比時,最後寬度是以子元素分到的寬度再乘以百分比得到。

Flex:
先以父元素的寬度計算各子元素的寬度,width 是百分比時,寬度是父元素的寬度乘以百分比來得到,之後再用 Flex 排版的方式決定是否寬度要進行延展、縮小或不變 ( 例如 flex-grow、flex-shrink、flex-basis 等設定)。

以下用實際例子來展示:

HTML:

<div class="grid stripes-background">
  <div>grid item1</div>
  <div>grid item2</div>
</div>

<div class="flex stripes-background">
  <div>flex item1</div>
  <div>flex item2</div>
</div>

CSS:

.stripes-background {
  background-image: linear-gradient(45deg, #000 25%, transparent 25%, transparent 50%, #000 50%, #000 75%, transparent 75%, #fff);
  background-size: 50px 50px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}

.flex {
  background-color: yellow;
  display: flex;
}

.grid div, .flex div {
  border: 1px solid black;
  width: 50%;
  background-color: rgba(0, 256, 0, 0.7);
}

JsFiddle 的線上範例

範例中有兩個區塊,分別使用了 display grid 和 flex,並在父元素和子元素上畫上背景來較好的分辨子元素寬度的分配。

可以看到子元素被設定了 width: 50%;,

在 grid 佈局中,子元素先以父元素的寬度用 flex 佈局計算好了應得的寬度,也就是
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
,然後才用應得的寬度乘上 50% 得到最後的寬度。

而 flex 佈局中,子元素先以父元素的寬度乘上 50% 得到應得的寬度,之後才進行 flex 佈局,而此例剛好沒有要對子元素寬度進行增縮。

簡單地來說,

Grid 是先在父元素把分配的空間格線畫好,再把子元素放進各空間中,此時子元素的 100% 寬度就是所處空間的寬度,最後各子元素再根據自己的 width 屬性設定計算寬度。

而 Flex 是子元素先根據自己的 width 屬性計算寬度,100% 寬度就是父元素的寬度,接著再用 Flex 進行排版決定各子元素在空間上的排列位置,最後再看有沒有要用 flex-grow、flex-shrink、flex-basis 等設定增縮子元素的寬度。

2022年7月11日 星期一

自訂 <ol> <li> 的項目標式方式 (list-style-type 配合 @counter-style)

html 中 <ol> <li> 的項目標式方式,可以使用 css 的 list-style-type 屬性配合  @counter-style 來自訂項目顯示方式,這裡演示一個將
list-style-type : trad-chinese-informal
擴展成自己想要的項目清單顯示方式,例如此例把
一、二、三
改成:
(一)、(二)、(三)

源碼如下:
Html:
<ol class="my-custom-list-style">
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ol>
CSS:
ol.my-custom-list-style {
  list-style-type: my-custom-list-style-type;
}

@counter-style my-custom-list-style-type {
  prefix: "(";
  suffix: ")";
  system: extends trad-chinese-informal;
}
成品如下:

2019年12月9日 星期一

RWD <table> - 純 html, css - 無 javascript

這篇紀錄了學到的 <table> RWD  的純 html, css 顯示技巧。
雖然在現今的 RWD 網站設計裡,因為 <table>的一些缺點,
通常都還是建議以不要用 <table> 的方式去做設計 (改用 <div>....等)。

但有時我們還是會有需要用到 <table> 的情況,
例如:

  1. 因為某些原因難以重改 html 結構 (含有 <table> ) 的網站 (老專案、時程、人力、需求等 ......)。
  2. <table> 在表示列表型資料時的方便性,居中對齊、控制寬度容 (雖然通常代表寬度 無法 RWD) 易等。

如果真得要用 <table> 時,有辦法加上一些 RWD 的效果嗎?
以下為 <table> RWD CSS 的範例,先看在 JSFiddle 的成果展示:



如果是寬螢幕的話,會是如下顯示:



如果是窄螢幕的話,就會是如下顯示:



再來看 html 結構及 CSS:

 html :
<table class="rwd-table">
  <tr>
    <th></th>
    <th>Very poor</th>
    <th>Poor</th>
    <th>Fair</th>
    <th>Good</th>
    <th>Very good</th>
  </tr>
  <tr>
    <td data-th="">Score 1 :</td>
    <td data-th="Very poor"><input type="radio" name="Score1"/></td>
    <td data-th="Poor"><input type="radio" name="Score1"/></td>
    <td data-th="Fair"><input type="radio" name="Score1"/></td>
    <td data-th="Good"><input type="radio" name="Score1"/></td>
    <td data-th="Very good"><input type="radio" name="Score1"/></td>
  </tr>
  <tr>
    <td data-th="">Score 1 :</td>
    <td data-th="Very poor"><input type="radio" name="Score2"/></td>
    <td data-th="Poor"><input type="radio" name="Score2"/></td>
    <td data-th="Fair"><input type="radio" name="Score2"/></td>
    <td data-th="Good"><input type="radio" name="Score2"/></td>
    <td data-th="Very good"><input type="radio" name="Score2"/></td>
  </tr>
  <tr>
    <td data-th="">Score 1 :</td>
    <td data-th="Very poor"><input type="radio" name="Score3"/></td>
    <td data-th="Poor"><input type="radio" name="Score3"/></td>
    <td data-th="Fair"><input type="radio" name="Score3"/></td>
    <td data-th="Good"><input type="radio" name="Score3"/></td>
    <td data-th="Very good"><input type="radio" name="Score3"/></td>
  </tr>
</table>

在 html 裡,只是放了一個普通的 <table> ,並在其加上了一個class, "rwd-table" 做為 rwd table 的 css selector,
另一個是我們用了 data-th (屬性名可自取) 這個屬性來記錄每個 <td> 對應的 <th> 標題值,
以利在窄螢幕時,可以用 css 的 :before 或 :after 偽元素中的 content 來取得標題值。

CSS:
/* normal table css */
/* normal table css */
table {
    border-collapse: collapse;
    border-spacing: 0;
}

table tr td, table tr th{
  border : 1px solid black;
}

table tr:nth-child(even){
  background-color : #d0aaaa;
}

/* rwd table css */
.rwd-table {
 overflow: hidden;
}

.rwd-table {
  min-width: 100%;
}

.rwd-table th {
  display: none;
}

.rwd-table td {
  display: block;
}

.rwd-table td:after {
  content: attr(data-th);
  display: inline-block;
}


.rwd-table tr {
    margin-bottom: 5px;
    display: inline-block;
    width: 100%;
}

@media (min-width: 583px) {
  .rwd-table td:after {
    display: none;
  }
 .rwd-table th, .rwd-table td {
    display: table-cell;
  }
  .rwd-table tr {
    margin-bottom: 0px;
    display: table-row;
  }
  
}

在 CSS 中,只要注意關於 .rwd-table 的部份 (即注解 /* rwd table css */ 以下的部份),
重點就是:

  1. 在寬螢幕時:
    1. th 正常顯示
    2. td:after 或 td:before 不顯示
    3. th, td 使用 display: table-cell
    4. tr 使用 display: table-row
  2. 在窄螢幕時:
    1. th 不顯示
    2. td:after 或 td:before 顯示,使用 content : attr(data-th) 全得 td 上的 data-th 屬性值
    3. td 使用 display: block
    4. tr 使用 display: inline-block


參考資料:
  1. Bootstrap教學-實現Table表格也支援RWD自適應效果
  2. 利用 Pure CSS 讓 HTML Table 也能有 RWD 效果 - Yowko's Notes
  3. 使用CSS製作響應式破壞式表格

2015年10月11日 星期日

CSS3的動畫

這裡紀錄一下利用CSS做簡單動畫的方法:
在CSS裡,可以利用animation-name屬性來指定動畫,並且利用@keyframes檢設定動畫

下面是一個簡單的例子,設定動畫為一秒,使用myAnim的自訂影格,影格內容分三個時間點(0%,50%和100%),動畫為左移動:
html:
<div class="animClass">我在移動</div>


css:
.animClass {

      animation-name: myAnim;   

      animation-duration: 1s;     

    

    }



@keyframes myAnim {

  0% {

      padding-left: 100%;

  }

  50% {

      padding-left: 0%;

  }

  100% {

      padding-left: 100%;

  }

}


線上實例演示:
http://jsfiddle.net/rd0zsy78/1/

CSS的動畫使用方法就跟平常使用CSS定義的一樣,用CSS選擇器來為選擇的元素定義動畫,包括了動畫名稱(animation-name)、持續時間(animation-duration)、重覆幾次(animation-iteration-count)等屬性可以設定。

接著就要自已定義對應影片名的關鍵影格,設定不同時間點(用百分比算)的CSS變化。

下面的參考資料就有詳細的各種參數資料可查詢。

參考資料

  1. CSS 動畫
  2. 使用 CSS Animation 製作網頁上的動畫(隻要 CSS3,不用 JavaScript!)
  3. CSS參考手冊

2015年3月15日 星期日

使用線上免費網頁樣式CSS風格(以JSP為例)

在撰寫網頁時,我們通常會為html另外寫CSS來設定其樣式,讓網頁各頁面的版面可以有一個統一的樣式風格,也比較好管理。

除了自己撰寫CSS外,還可以從網路上找到許多免費的樣式資源,可以免費的下載下來使用,有的是就是一個單統的CSS檔,而有的稍微用了其他的方法來匯入CSS檔(例如JQuery),而CSS的路徑的也要設正確。總之根據不同的免費CSS資源,需要稍微的修改一下才能使用。

Templated是一個提供各種網頁樣式的網站,有許多的免費樣式可以下載使用。因為在之前的使用上花了一點時間搞定,特在此紀錄一下以Templated網站中的一個樣式Transit為例的使用方法。

進入Transit頁面後(如下圖),可以在上面橫幅的右邊下載其樣式,在Elements的連結中可以點進去看到此樣式的各個html元件的樣子,可以看看自己喜不喜歡在下載使用。


下載下來解壓縮後,可以看到如下的檔案結構,其中根目錄的三個html是網頁範例,css、fonts、images、js各是CSS、字型、圖片和JQuery資料夾。