整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          動(dòng)手練一練,用純 CSS 制作一款側(cè)滑顯示留言面板的網(wǎng)頁(yè)組件


          家好,不知道你們是否和我一樣存在這樣的困惑呢,雖然css入門(mén)容易,但是其內(nèi)容太多,好多屬性看了似是而非,覺(jué)得自己看懂了,到自己用的時(shí)候又很犯難了,看到漂亮的效果還是無(wú)從下手,這主要還是自己對(duì)新屬性實(shí)踐太少了,不能進(jìn)行靈活應(yīng)用,CSS總讓一些人找不到感覺(jué)。其實(shí)學(xué)好CSS真的沒(méi)有太多捷徑,和JS編程一樣,要重視對(duì)待,要多看和多練,因?yàn)楝F(xiàn)在的CSS不再是以前的CSS啦。

          比如這兩本書(shū)《 CSS 權(quán)威指南第四版》,1000多頁(yè),買(mǎi)了好幾個(gè)月我到現(xiàn)在還沒(méi)看完,文字實(shí)在太枯燥了,看完了忘,忘了繼續(xù)看,實(shí)在看不下去,不知道大家有沒(méi)有同樣的感受呢?

          好了,廢話(huà)不多說(shuō),今天我們要做的一個(gè)案例就是做一個(gè)常見(jiàn)的例子:在不少網(wǎng)站右側(cè)都有一個(gè)固定浮動(dòng)的留言圖標(biāo),我們點(diǎn)擊這個(gè)圖標(biāo),就會(huì)側(cè)滑顯示留言?xún)?nèi)容面板。你也許會(huì)說(shuō)這個(gè)不簡(jiǎn)單嗎,使用JQ就能輕松實(shí)現(xiàn),但是我想說(shuō)的,為了網(wǎng)站的性能,能用CSS實(shí)現(xiàn)的盡量不要用JS,因?yàn)楝F(xiàn)在CSS已足夠強(qiáng)大。

          今天這個(gè)例子,我們將使用純CSS實(shí)現(xiàn)這個(gè)效果,這里我們將用到” CSS checkbox hack“的技術(shù),效果如下圖所示:


          一、創(chuàng)建 HTML 結(jié)構(gòu)

          基于上面的效果圖,我們要?jiǎng)?chuàng)建三個(gè)元素,一個(gè) checkbox 元素以及對(duì)應(yīng)的 label 標(biāo)記,和一個(gè)表單面板元素。

          這里用到了一個(gè) CSS 特性值得大家關(guān)注下:<label> 標(biāo)簽的 for 屬性用于指定與哪個(gè)表單元素進(jìn)行關(guān)聯(lián),擴(kuò)大表單元素的點(diǎn)擊區(qū)域,我們點(diǎn)擊 label 元素標(biāo)記,其對(duì)應(yīng)的表單元素將會(huì)被聚焦選中。

          這個(gè)特性是我們實(shí)現(xiàn)這個(gè)案例的技巧之一,再結(jié)合 CSS checkbox 的偽類(lèi)選擇器進(jìn)行留言面板的顯示與隱藏,這樣我們就可以擺脫 JS 來(lái)實(shí)現(xiàn)這個(gè)案例。

          基于以上思路 ,我們開(kāi)始動(dòng)手吧,首先我們先放置 checkbox,和其對(duì)應(yīng)的 label,最后添加表單面板和相關(guān)的表單元素。

          我們將通過(guò)表單的 id 屬性與表單中l(wèi)abel元素的 for 值與其關(guān)聯(lián),最終我們完成了 HTML 結(jié)構(gòu)如下段代碼所示:

          <input type="checkbox" id="mycheckbox">
          <label for="mycheckbox" class="feedback-label">FEEDBACK</label>
          <form class="form">
            <div>
              <label for="fullname">Full Name</label>
              <input type="text" id="fullname">
            </div>
            <div>
              <label for="email">Email</label>
              <input type="email" id="email">
            </div>
            <div>
              <label for="comment">Comment</label>
              <textarea id="comment"></textarea>
            </div>
            <div>
              <button type="submit">Send</button>
            </div>
          </form>
          

          完成后的效果圖如下:

          二、定義基礎(chǔ)的樣式

          現(xiàn)在我們開(kāi)始添加一些基礎(chǔ)的CSS的式,這里我們用到了CSS自定義變量,方便我們?nèi)中薷模€有一些 reset 規(guī)則,和表單的基礎(chǔ)規(guī)則樣式,示例代碼如下:

          :root {
            --white: white;
            --gradient: linear-gradient(-45deg, #FFA600 0%, #FF5E03 50%);
            --form: #eeefef;
            --border-radius: 4px;
            --form-width: 500px;
            --form-mob-width: 320px;
          }
           
          * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
          }
          
          body {
            font: 20px/1.5 sans-serif;
            background: var(--white);
          }
          
          h1 {
            font-size: 2rem;
            text-align: center;
            margin-top: 20vh;
          }
           
          button,
          label {
            cursor: pointer;
          }
           
          label {
            display: block;
          }
           
          button,
          input,
          textarea {
            font-family: inherit;
            font-size: 100%;
            border: none;
          }
           
          textarea {
            resize: none;
          }
          

          三、 定義表單元素相關(guān)樣式

          1、由于 checkbox 這個(gè)元素在案例中無(wú)需顯示,我們只是用其的偽類(lèi)特性結(jié)合 label 控制留言面板的顯示與隱藏,因此我們需要將其移出可視區(qū)域,記住這里不能用隱藏屬性(display:none)。示例代碼如下:

          [type="checkbox"] {
            position: absolute;
            left: -9999px;
          }
          

          2、接下來(lái),我們需要添加這些CSS操作:

          • 使用 fix 屬性將 checkbox 對(duì)應(yīng)的 label 標(biāo)簽元素固定在右側(cè)的中央。
          • 垂直先顯示”FEEDBACK“文本。
          • 隱藏表單面板,我們這里將其往右移動(dòng)其寬度的 100% 的距離,并垂直居中。

          對(duì)應(yīng)的CSS代碼如下:

          /*CUSTOM VARIABLES HERE*/
          .feedback-label,
          .form {
            position: fixed;
            top: 50%;
            right: 0;
          }
           
          .feedback-label {
            transform-origin: top right;
            transform: rotate(-90deg) translate(50%, -100%);
            z-index: 2;
          }
           
          .form {
            width: var(--form-width);
            max-height: 90vh;
            transform: translate(100%, -50%);
            padding: 30px;
            overflow: auto;
            background: var(--form);
            z-index: 1;
          }
          

          小提示:

          1、這里需要強(qiáng)調(diào)的是 feedback-label 樣式,在其垂直變換時(shí),我們先逆時(shí)針進(jìn)行了旋轉(zhuǎn),其 x ,y 軸的方向也是隨著旋轉(zhuǎn)的,所以是translate(50%, -100%),將其垂直居中。

          2、在 form 樣式里,我們使用 transform 方法,translate(100%, -50%) 將其移出頁(yè)面顯示區(qū)域

          3、我們繼續(xù),大家不要著急,馬上就快完成了,我們需要將頁(yè)面弄的漂亮些,添加一些樣式,示例代碼如下:

          /*CUSTOM VARIABLES HERE*/
           
          .feedback-label,
          .form input,
          .form textarea,
          .form button {
            border-radius: var(--border-radius);
          }
           
          .feedback-label,
          .form button {
            background: var(--gradient);
            color: var(--white);
          }
           
          .feedback-label:hover,
          .form button:hover {
            filter: hue-rotate(-45deg);
          }
           
          .feedback-label {
            padding: 5px 10px;
            border-radius: var(--border-radius) var(--border-radius) 0 0;
          }
           
          form div:not(:last-child) {
            margin-bottom: 20px;
          }
           
          form div:last-child {
            text-align: right;
          }
           
          .form input,
          .form textarea {
            padding: 0 5px;
            width: 100%;
          }
           
          .form button {
            padding: 10px 20px;
            width: 50%;
            max-width: 120px;
          }
           
          .form input {
            height: 40px;
          }
           
          .form textarea {
            height: 220px;
          }
          

          小提示:這里我們的背景色用到了 linear-gradient() 線(xiàn)性漸變,實(shí)現(xiàn)了一個(gè)漂亮的顏色漸變背景。還有一個(gè) CSS3 語(yǔ)法需要關(guān)注下:hue-rotate,色調(diào)旋轉(zhuǎn)濾鏡,方便我們改變當(dāng)前的顏色。

          四、使用CSS選擇器,實(shí)現(xiàn)表單面板的切換和隱藏

          我們通過(guò)點(diǎn)擊 checkbox 對(duì)應(yīng)的 label 標(biāo)簽進(jìn)行切換和顯示留言面板,這里我們用到了 :checked 偽類(lèi),以及 ~(后續(xù)同胞選擇器)和 +(緊鄰?fù)x擇器),輔助元素的選擇進(jìn)行樣式變換,示例代碼如下:

          [type="checkbox"]:checked + .feedback-label {
            transform: rotate(-90deg) translate(50%, calc((var(--form-width) + 100%) * -1));
          }
           
          [type="checkbox"]:focus + .feedback-label {
            outline: 2px solid rgb(77, 144, 254);
          }
           
          [type="checkbox"]:checked ~ .form {
            transform: translate(0, -50%);
          }
           
          .feedback-label,
          .form {
            transition: all 0.35s ease-in-out;
          }
          

          這里有幾個(gè)樣式規(guī)則我們需要聊一下:

          1. translate(50%, calc((var(--form-width) + 100%) * -1)); 這個(gè)樣式是不是有些復(fù)雜,其實(shí)也不難,就是多加了一個(gè)表單面板的寬度,由于旋轉(zhuǎn)后,y軸變成了水平軸,向左移動(dòng)相當(dāng)Y軸往上移動(dòng),因此是負(fù)值,需要乘-1。
          2. 第二個(gè)選擇器,我們之所以加個(gè)選中后的 outline 輪廓屬性,主要是為了方便那些習(xí)慣鍵盤(pán)操作的用戶(hù),當(dāng)其使用 Tab 鍵選擇 feedback label元素時(shí),然后再使用 Space 空格鍵就能很方便的打開(kāi)留言面板進(jìn)行切換。
          3. 第三個(gè)選擇器,我們使用 transform: translate(0, -50%); 將 X 軸更改成0,恢復(fù)成最開(kāi)始的位置,這樣我們的留言面板內(nèi)容就能顯示出來(lái)。

          處理響應(yīng)式問(wèn)題

          最后,特別重點(diǎn)提示下我們做頁(yè)面要考慮頁(yè)面響應(yīng)式適配的問(wèn)題,這里我們需要針對(duì)手機(jī)設(shè)備做一些樣式的調(diào)整,比如更改表單面板的寬度由原來(lái)的 500px 調(diào)整到 320px,以及初始字體的大小,調(diào)整成16px。

          最終添加的響應(yīng)式代碼如下:

          /*CUSTOM VARIABLES HERE*/
           
          @media screen and (max-width: 600px) {
            body {
              font-size: 16px;
            }
           
            .form {
              padding: 15px;
              width: var(--form-mob-width);
            }
           
            form div:not(:last-child) {
              margin-bottom: 10px;
            }
           
            [type="checkbox"]:checked + .feedback-label {
              transform: rotate(-90deg) translate(50%, calc((var(--form-mob-width) + 100%) * -1));
            }
          }
          

          小節(jié)

          好了,到這里,我們的案例就全部完成了,你可以欣賞下自己完成的杰作啦,實(shí)現(xiàn)起來(lái)是不是很簡(jiǎn)單呢,最后我還是建議大家還是親自動(dòng)手實(shí)踐一遍,這樣才能加深對(duì)本案例用到的CSS屬性的理解。

          最終完成的效果,大家可以點(diǎn)擊以下網(wǎng)址進(jìn)行在線(xiàn)體驗(yàn):

          https://www.qianduandaren.com/demo/feedback/

          今天的內(nèi)容就和大家分享到這里,感謝你的閱讀,如果你喜歡我的分享,麻煩給個(gè)關(guān)注、點(diǎn)贊加轉(zhuǎn)發(fā)哦,你的支持,就是我分享的動(dòng)力,后續(xù)會(huì)持續(xù)分享 CSS 常用案例和技巧,歡迎持續(xù)關(guān)注。

          延伸閱讀

          基礎(chǔ)章節(jié):這30個(gè)CSS選擇器,你必須熟記(上)

          基礎(chǔ)章節(jié):這30個(gè)CSS選擇器,你必須熟記(中)

          基礎(chǔ)章節(jié):這30個(gè)CSS選擇器,你必須熟記(下)

          使用 CSS Checkbox Hack 技術(shù)制作一個(gè)手風(fēng)琴組件

          擊右上方紅色按鈕關(guān)注“web秀”,讓你真正秀起來(lái)

          前言

          隨著前端開(kāi)發(fā)越來(lái)越關(guān)注效率:通過(guò)選擇器的使用和簡(jiǎn)化代碼來(lái)快速加載渲染。像Less、SCSS這樣的預(yù)處理器在工作的時(shí)候,需要繞的路較長(zhǎng),而直接使用css速度會(huì)更快。這里涵蓋了20個(gè)css技巧來(lái)幫助你減少重復(fù)規(guī)則和復(fù)寫(xiě),在布局中標(biāo)準(zhǔn)化樣式流程,不僅可以幫助你高效地創(chuàng)建自己的框架,而且可以解決許多常見(jiàn)的問(wèn)題。

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          如果您對(duì)CSS比較陌生,看看這篇文章CSS選擇器如此之多,你了解多少?

          1、使用CSS重置(reset)

          css重置庫(kù)如normalize.css已經(jīng)被使用很多年了,它們可以為你的網(wǎng)站樣式提供一個(gè)比較清晰的標(biāo)準(zhǔn),來(lái)確保跨瀏覽器之間的一致性。大多數(shù)項(xiàng)目并不需要這些庫(kù)包含的所有規(guī)則,可以通過(guò)一條簡(jiǎn)單的規(guī)則來(lái)應(yīng)用于布局中的所有元素,刪除所有的margin、padding改變?yōu)g覽器默認(rèn)的盒模型。

          *{ 
           box-sizing:border-box; 
           margin:0; 
           padding:0 
          }
          

          使用box-sizing聲明是可選擇,如果你使用下面繼承的盒模型形式可以跳過(guò)它

          2、繼承盒模型

          讓盒模型從html 繼承:

          html { 
           box-sizing: border-box; 
          } 
          *, *:before, *:after { 
           box-sizing: inherit; 
          }
          

          3、使用flexbox布局來(lái)避免margin的問(wèn)題 (Get Rid of Margin hacks width Flexbox)

          當(dāng)你多少次試著去設(shè)計(jì)柵格布局如:組合或者圖片畫(huà)廊,如果使用浮動(dòng)的方式,那么就需要去清除浮動(dòng)和重置外邊距來(lái)使其分解成所需要行數(shù)。為了避免nth-、first-、last-child 問(wèn)題 ,可以使用flexbox 的space-between 屬性值

          .flex-container{ 
           display:flex; 
           justify-content:space-between; 
          } 
          .flex-container .item{ 
           flex-basis:23%; 
          }
          

          4、使用:not() 解決lists邊框的問(wèn)題

          在web設(shè)計(jì)中,我們通常使用:last-child nth-child 選擇器來(lái)覆蓋原先聲明應(yīng)在父選擇器上的樣式。比如說(shuō)一個(gè)導(dǎo)航菜單,通過(guò)使用borders 來(lái)給每個(gè)鏈接Link創(chuàng)建分割符,然后再在加上一條規(guī)則 解除最后一個(gè)link的border

          .nav li { 
           border-right: 1px solid #666; 
          } 
          .nav li:last-child { 
           border-right: none; 
          }
          

          這是一種很混亂的方式,它不僅強(qiáng)制瀏覽器以一種方式渲染,然后又通過(guò)特定的選擇器來(lái)撤銷(xiāo)它。這樣覆蓋樣式是不可避免的。然而,最重要的是,我們可以通過(guò)使用:not偽類(lèi)(pseudo-class) 在你想聲明的元素上僅僅只使用一種樣式:

          .nav li:not(:last-child) { 
           border-right: 1px solid #666; 
          }
          

          上面就是,除了最后一個(gè)li以外,所有的 .nav li 都加上了border樣式,是不是很簡(jiǎn)單! 當(dāng)然,你也可以使用 .nav li+li或者 .nav li:first-child ~li ,但是 :not是更有語(yǔ)義化(semantic)和容易理解的。

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          5、body上加入line-height樣式

          導(dǎo)致低樣式效率(inefficient stylesheets)的一件事就是不斷的重復(fù)聲明。最好是做下項(xiàng)目規(guī)劃和組合規(guī)則,這樣CSS會(huì)更流暢。實(shí)現(xiàn)這一點(diǎn),就需要我們理解級(jí)聯(lián)(cascade),以及如何在通用選擇器寫(xiě)的樣式可以繼承在其他地方。行間距(line-height)可以作為 給你的整個(gè)項(xiàng)目設(shè)置的一個(gè)屬性,不僅可以減小代碼量,而且可以讓你的網(wǎng)站的樣式給一個(gè)標(biāo)準(zhǔn)的外觀

          body { 
           line-height: 1.5; 
          }
          

          請(qǐng)注意,這里的聲明沒(méi)有單位,我們只是告訴瀏覽器 讓它渲染行高是 渲染字體大小的1.5倍

          6、垂直居中任何元素 (vertical-center anything)

          在沒(méi)有準(zhǔn)備使用CSSGrid 布局的時(shí)候,設(shè)置垂直居中布局的全局規(guī)則是一個(gè)很好的方式,可以為優(yōu)雅(elegantly)的設(shè)置內(nèi)容布局奠定一個(gè)基礎(chǔ)

          html, body { 
           height: 100%; 
           margin: 0; 
          } 
          body { 
           -webkit-align-items: center; 
           -ms-flex-align: center; 
           align-items: center; 
           display: -webkit-flex; 
           display: flex; 
          }
          

          這15種CSS居中的方式,你都用過(guò)哪幾種?

          7、使用SVG icons

          SVG使用于所有分辨類(lèi),并且所有瀏覽器也都支持。所以可以將.png .jpg .gif 等文件 丟棄。FontAwsome5中 也提供了SVG的圖標(biāo)字體。設(shè)置SVG的格式就跟其他圖片類(lèi)型一樣:

          .logo { 
           background: url("logo.svg"); 
          }
          

          溫馨提示:如果將SVG用在可交互的元素上比如說(shuō)button,SVG 會(huì)產(chǎn)生無(wú)法加載的問(wèn)題。可以通過(guò)下面這個(gè)規(guī)則來(lái)確保SVG可以訪問(wèn)到(確保在HTML中已設(shè)置適當(dāng)?shù)腶ria屬性)

          .no-svg .icon-only:after { 
           content: attr(aria-label); 
          }
          

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          8、使用 “OWL選擇器”

          使用通用選擇器(universal selector)* 和相鄰的兄弟選擇器(adjacent sibling selector)+ 可以提供一個(gè)強(qiáng)大的的CSS功能,給緊跟其他元素中的文檔流中的所有元素設(shè)置統(tǒng)一的規(guī)則

          * + * { 
           margin-top: 1.5rem; 
          }
          

          這是一個(gè)很棒的技巧,可以幫你創(chuàng)建更加均勻的類(lèi)型跟間距。在上面的列子中,跟在其他元素后面的元素,比如說(shuō)H3后面的H4,或者一個(gè)段落之后的一個(gè)段落,他們之間至少1.5rems的間距(大約為30px)

          9、一致的垂直結(jié)構(gòu)(Consistent Vertical Rhythm)

          一致的垂直節(jié)奏提供了一種視覺(jué)美學(xué),使內(nèi)容更具可讀性。如果owl選擇器過(guò)于通用,請(qǐng)?jiān)谠貎?nèi)使用通用選擇器(*)為布局的特定部分創(chuàng)建一致的垂直節(jié)奏:

          .intro > * { 
           margin-bottom: 1.25rem; 
          }
          

          10、對(duì)更漂亮的換行文本使用 box-decoration-break

          假設(shè)您希望對(duì)換行到多行的長(zhǎng)文本行應(yīng)用統(tǒng)一的間距、邊距、突出顯示或背景色,但不希望整個(gè)段落或標(biāo)題看起來(lái)像一個(gè)大塊。Box Decoration Break屬性允許您僅對(duì)文本應(yīng)用樣式,同時(shí)保持填充和頁(yè)邊距的完整性。如果要在懸停時(shí)應(yīng)用突出顯示,或在滑塊中設(shè)置子文本樣式以具有突出顯示的外觀,則此功能尤其有用:

          .p { 
           display: inline-block; 
           box-decoration-break: clone; 
           -o-box-decoration-break: clone; 
           -webkit-box-decoration-break: clone; 
          }
          

          內(nèi)聯(lián)塊聲明允許將顏色、背景、頁(yè)邊距和填充應(yīng)用于每行文本,而不是整個(gè)元素,克隆聲明確保將這些樣式均勻地應(yīng)用于每行。

          11、等寬表格單元格

          表格可能很難處理,所以嘗試使用table-layout:fixed來(lái)保持單元格相等寬度:

          .calendar { 
           table-layout: fixed; 
          }
          

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          12、強(qiáng)制使用屬性選擇器顯示空鏈接

          這對(duì)于通過(guò)CMS插入的鏈接特別有用,CMS通常不具有類(lèi)屬性,并幫助您在不影響級(jí)聯(lián)的情況下對(duì)其進(jìn)行特定樣式設(shè)置。例如,<a>元素沒(méi)有文本值,但href屬性有一個(gè)鏈接:

          a[href^="http"]:empty::before { 
           content: attr(href); 
          }
          

          13、樣式“默認(rèn)”鏈接

          說(shuō)到鏈接樣式,您可以在幾乎每個(gè)樣式表中找到一個(gè)通用的A樣式。這迫使您為子元素中的任何鏈接編寫(xiě)額外的覆蓋和樣式規(guī)則,并且在使用像WordPress這樣的CMS時(shí),可能會(huì)導(dǎo)致您的主鏈接樣式比按鈕文本顏色更容易出現(xiàn)問(wèn)題。嘗試這種較少干擾的方式為“默認(rèn)”鏈接添加樣式:

          a[href]:not([class]) { 
           color: #999; 
           text-decoration: none; 
           transition: all ease-in-out .3s;
          }
          

          14、比率框

          要?jiǎng)?chuàng)建具有固有比率的框,您需要做的就是將頂部或底部填充應(yīng)用于div:

          .container { 
           height: 0; 
           padding-bottom: 20%; 
           position: relative; 
          } 
          .container div { 
           border: 2px dashed #ddd; 
           height: 100%; 
           left: 0; 
           position: absolute; 
           top: 0; 
           width: 100%; 
          }
          

          使用20%進(jìn)行填充使得框的高度等于其寬度的20%。無(wú)論視口的寬度如何,子div都將保持其縱橫比(100%/ 20%= 5:1)。

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          15、風(fēng)格破碎的圖像

          這個(gè)技巧不是關(guān)于代碼縮減,而是關(guān)于細(xì)化設(shè)計(jì)細(xì)節(jié)的。破碎的圖像發(fā)生的原因有很多,要么不雅觀,要么導(dǎo)致混亂(只是一個(gè)空元素)。用這個(gè)小小的CSS創(chuàng)建更美觀的效果:

          img { 
           display: block; 
           font-family: Helvetica, Arial, sans-serif; 
           font-weight: 300; 
           height: auto; 
           line-height: 2; 
           position: relative; 
           text-align: center; 
           width: 100%; 
          } 
          img:before { 
           content: "We're sorry, the image below is missing :("; 
           display: block; 
           margin-bottom: 10px; 
          } 
          img:after { 
           content: "(url: " attr(src) ")"; 
           display: block; 
           font-size: 12px; 
          }
          

          16、使用rem進(jìn)行全局大小調(diào)整;使用em進(jìn)行局部大小調(diào)整

          在設(shè)置根目錄的基本字體大小后,例如html字體大小:15px;,可以將包含元素的字體大小設(shè)置為rem:

          article { 
           font-size: 1.25rem; 
          } 
          aside { 
           font-size: .9rem; 
          }
          

          然后將文本元素的字體大小設(shè)置為em

          h2 { 
           font-size: 2em; 
          } 
          p { 
           font-size: 1em; 
          }
          

          現(xiàn)在,每個(gè)包含的元素都變得分區(qū)化,更易于樣式化、更易于維護(hù)和靈活。

          web開(kāi)發(fā)中該用 em 還是 rem 呢?

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          17、隱藏未靜音的自動(dòng)播放視頻

          當(dāng)您處理無(wú)法從源代碼輕松控制的內(nèi)容時(shí),這對(duì)于自定義用戶(hù)樣式表來(lái)說(shuō)是一個(gè)很好的技巧。這個(gè)技巧將幫助您避免在加載頁(yè)面時(shí)自動(dòng)播放視頻中的聲音干擾訪問(wèn)者,并再次提供了精彩的:not()偽選擇器:

          video[autoplay]:not([muted]) { 
           display: none; 
          }
          

          18、靈活運(yùn)用root類(lèi)型

          響應(yīng)布局中的字體大小應(yīng)該能夠自動(dòng)調(diào)整到視區(qū),從而保存編寫(xiě)媒體查詢(xún)的工作,以處理字體大小。可以使用:not和視區(qū)單位,根據(jù)視區(qū)高度和寬度計(jì)算字體大小:

          :root { 
           font-size: calc(1vw + 1vh + .5vmin); 
          }
          

          現(xiàn)在,您可以使用根em單位,該單位基于:not:

          body { 
           font: 1rem/1.6 sans-serif; 
          }
          

          結(jié)合上面的rem/em技巧以獲得更好的控制。有關(guān)管理Safari舊版本的提示,請(qǐng)參閱CSS Fix for iOS VH Unit Bug。

          19、在表單元素上設(shè)置字體大小,以獲得更好的移動(dòng)體驗(yàn)

          為了避免移動(dòng)瀏覽器(iOS Safari等)在點(diǎn)擊<select>下拉列表時(shí)放大HTML表單元素,請(qǐng)?jiān)谔砑觙ont-size樣式:

          input[type="text"], 
          input[type="number"], 
          select, 
          textarea { 
           font-size: 16px; 
          }
          

          20、CSS變量

          最后,最強(qiáng)大的CSS級(jí)別來(lái)自于CSS變量,它允許您聲明一組公共屬性值,這些值可以通過(guò)樣式表中任何位置的關(guān)鍵字重用。你可能有一套顏色在整個(gè)項(xiàng)目中使用,以保持一致性。在CSS中反復(fù)重復(fù)這些顏色值不僅是件煩人的事情,而且還容易出錯(cuò)。如果某個(gè)顏色在某個(gè)時(shí)刻需要改變,你就不得不去尋找和替換,這是不可靠或不快速的,當(dāng)為最終用戶(hù)構(gòu)建產(chǎn)品時(shí),變量使得定制變得容易得多。例如:

          如何提升你的CSS技能?掌握這20個(gè)css技巧即可[完整版]

          :root { 
           --main-color: #06c; 
           --accent-color: #999; 
          } 
           
          h1, h2, h3 { 
           color: var(--main-color); 
          } 
          a[href]:not([class]), 
          p, 
          footer span{ 
           color: var(--accent-color); 
          }
          

          公告

          喜歡小編的點(diǎn)擊關(guān)注,了解更多知識(shí)!

          何保持頁(yè)面樣式基本不變的前提下將HTML頁(yè)面導(dǎo)出為PDF,下面提供一些示例代碼,純屬個(gè)人原創(chuàng),如對(duì)你有幫助請(qǐng)記得加關(guān)注、加收藏、點(diǎn)贊、轉(zhuǎn)發(fā)、分享~謝謝~~

          • 基本思路:保持頁(yè)面樣式基本不變,使用 `html2canvas` 將頁(yè)面轉(zhuǎn)換為圖片,然后再通過(guò) `jspdf` 將圖片分頁(yè)導(dǎo)出為PDF文件(中間會(huì)遇到圖片或文字等內(nèi)容在分頁(yè)處被切割開(kāi)的問(wèn)題,如何解決了?詳見(jiàn)末尾干貨)
          • 上基礎(chǔ)代碼:下面為項(xiàng)目中實(shí)際代碼截取
          <div>
              <!-- 要打印的內(nèi)容區(qū) -->
              <div ref="contentRef">
                  <div class="print-item print-out-flow">這是脫離文檔流的內(nèi)容區(qū)域</div>
                  <div class="print-item">這是一行內(nèi)容,也是最小葉子元素內(nèi)容</div>
              </div>
              <!-- 打印內(nèi)容容器 -->
              <div ref="printContainerRef" class="print-container"></div>
          </div>
          /**
            * 1.使用一個(gè)隱藏div裝載有滾動(dòng)條的div.innerHTML
            * 2.隱藏div使用position: absolute, z-index: -999, left: -9999px, width: 900px 控制讓用戶(hù)無(wú)感知
            * 3.根據(jù)需要覆寫(xiě)隱藏div內(nèi)html樣式(例如textarea多行顯示有問(wèn)題, 可以新增一個(gè)隱藏的div
            *    包裹textarea的綁定值, 然后在打印樣式中覆寫(xiě)樣式, 隱藏textarea并顯示對(duì)應(yīng)div)
            */
          handleExport() {
             // 下面是VUE組件內(nèi)獲取DOM元素代碼,將內(nèi)容放置到打印區(qū)(定義的隱藏DIV)中
              const contentRef = this.$refs.contentRef as HTMLElement;
              const printContainerRef = this.$refs.printContainerRef as HTMLElement;
              // 打印區(qū)的需額外處理絕對(duì)定位值, 調(diào)整使得第一個(gè)元素的.top值為0, 以便于頁(yè)面計(jì)算
              printContainerRef.innerHTML = contentRef.innerHTML;	
              
              // 所有葉子div元素加上 print-item 樣式名, 脫離文檔流的額外添加 print-out-flow
              handlePrintItem(printContainerRef);  // 解決多頁(yè)內(nèi)容可能被切割問(wèn)題
              
              html2canvas(printContainerRef, {allowTaint: false, useCORS: true}).then((canvas: any) => {
                const contentHeight = canvas.height;
                const contentWidth = canvas.width;
                // pdf每頁(yè)顯示的內(nèi)容高度
                const pageHeight = contentWidth / 595.28 * 841.89;
                // 未生成pdf的頁(yè)面高度
                let offsetHeight = contentHeight;
                // 頁(yè)面偏移值
                let position = 0;
                // a4紙的尺寸[595.28, 841.89], canvas圖片按a4紙大小縮放后的寬高
                const imgWidth = 595.28;
                const imgHeight = 595.28 / contentWidth * contentHeight;
          
                const dataURL = canvas.toDataURL('image/jpeg', 1.0);
                const doc = new jsPDF('p', 'pt', 'a4');
          
                if (offsetHeight < pageHeight) {
                  doc.addImage(dataURL, 'JPEG', 0, 0, imgWidth, imgHeight);
                } else {
                  while (offsetHeight > 0) {
                    doc.addImage(dataURL, 'JPEG', 0, position, imgWidth, imgHeight);
                    offsetHeight -= pageHeight;
                    position -= 841.89;
          
                    if (offsetHeight > 0) {
                      doc.addPage();
                    }
                  }
                }
          
                doc.save(this.generateReportFileName());
                printContainerRef.innerHTML = '';
              });
          }

          上干貨代碼:上面分頁(yè)導(dǎo)出PDF可能網(wǎng)上能看到類(lèi)型代碼,但絕對(duì)找不到下面的代碼,純手搓解決分頁(yè)元素被切開(kāi)問(wèn)題(思路:獲取自身定位,如自己剛好在被分頁(yè)處,則加上一定的margin-top值將內(nèi)容向下移)

          /** 
           * 處理打印元素項(xiàng), 修復(fù)分頁(yè)后被切割的元素
           * @param printContainerRef 打印內(nèi)容div容器
           * @param itemClassName 打印最小元素標(biāo)識(shí)類(lèi)名
           * @param outFlowClassName 脫離文檔流的元素標(biāo)識(shí)類(lèi)名
           */
          export function handlePrintItem(
            printContainerRef: HTMLElement,
            itemClassName: string = 'print-item',
            outFlowClassName: string = 'print-out-flow'
          ): void {
            const rootClientRect = printContainerRef.getBoundingClientRect();
            // 初始化頁(yè)面相關(guān)數(shù)據(jù)
            const totalHeight = rootClientRect.height;  // 內(nèi)容總高度
            const a4PageHeight = (printContainerRef.clientWidth / 595.28) * 841.89; // a4紙高度
            let pageNum = Math.ceil(totalHeight / a4PageHeight);  // 總頁(yè)數(shù)
            let addPageHeight = 0;  // 修正被分割元素而增加的頁(yè)面高度總和
            let currentPage = 1;  // 當(dāng)前正在處理切割的頁(yè)面
            const splitItemObj: { [key: number]: HTMLElement[] } = {};  // 內(nèi)容中各頁(yè)被切割元素存儲(chǔ)對(duì)象
          
            const printItemNodes: NodeListOf<HTMLElement> = printContainerRef.querySelectorAll(`.${itemClassName}`);
            for (let item of printItemNodes) {
              // 如果當(dāng)前頁(yè)已經(jīng)是最后一頁(yè), 則中斷判斷
              if (currentPage >= pageNum) {
                break;
              }
          
              // 獲取元素絕對(duì)定位數(shù)據(jù)
              const clientRect = item.getBoundingClientRect();
              let top = clientRect.top;
              const selfHeight = clientRect.height;
              // 如果當(dāng)前元素距離頂部高度大于當(dāng)前頁(yè)面頁(yè)腳高度, 則開(kāi)始判斷下一頁(yè)頁(yè)腳被切割元素
              if (top > currentPage * a4PageHeight) {
                // 換頁(yè)前修正上一頁(yè)被切割元素
                addPageHeight += fixSplitItems(currentPage, a4PageHeight, splitItemObj[currentPage], outFlowClassName);
                pageNum = Math.ceil((totalHeight + addPageHeight) / a4PageHeight);
                top = item.getBoundingClientRect().top;
                currentPage++;
              }
              // 如果元素剛好處于兩頁(yè)之間, 則記錄該元素
              if (top > (currentPage - 1) * a4PageHeight && top < currentPage * a4PageHeight && top + selfHeight > currentPage * a4PageHeight) {
                if (!splitItemObj[currentPage]) {
                  splitItemObj[currentPage] = [];
                }
                splitItemObj[currentPage].unshift(item);
                // 如果當(dāng)前元素是最后一個(gè)元素, 則直接處理切割元素, 否則交由處理下一頁(yè)元素時(shí)再處理切割
                if (item === printItemNodes[printItemNodes.length - 1]) {
                  fixSplitItems(currentPage, a4PageHeight, splitItemObj[currentPage], outFlowClassName);
                }
              }
            }
          }
          
          /**
            * 修復(fù)當(dāng)前頁(yè)所有被切割元素
            * @param currentPage 當(dāng)前頁(yè)
            * @param pageHeight 每頁(yè)高度
            * @param splitElementItems 當(dāng)前被切割元素?cái)?shù)組
            * @param outFlowClassName 脫離文檔流的樣式類(lèi)名
            */
          function fixSplitItems(
            currentPage: number,
            pageHeight: number,
            splitElementItems: HTMLElement[],
            outFlowClassName: string
          ): number {
            if (!splitElementItems || !splitElementItems.length) {
              return 0;
            }
          
            const yMargin = 5;  // y方向距離頁(yè)眉的距離
            const splitItemsMinTop = getSplitItemsMinTop(splitElementItems);
            if (!splitItemsMinTop) {
              return 0;
            }
          
            let fixHeight = currentPage * pageHeight - splitItemsMinTop + yMargin;
            const outFlowElement = splitElementItems.find((item) => item.classList.contains(outFlowClassName));
            if (outFlowElement && outFlowElement.parentElement) {
              const parentPreviousElement = outFlowElement.parentElement.previousElementSibling as HTMLElement;
              fixHeight += getMarinTopNum(parentPreviousElement, outFlowElement.parentElement);
              outFlowElement.parentElement.style.marginTop = `${fixHeight}px`;
              return fixHeight;
            }
          
            splitElementItems.forEach((splitElement) => {
              splitElement.style.marginTop = `${fixHeight}px`;
            });
            return fixHeight;
          }
          
          /**
            * 獲取被切割元素?cái)?shù)組中最小高度值(如一行有多個(gè)元素被切割,則選出距離頂部最小的高度值)
            * @param splitElementItems 當(dāng)前被切割元素?cái)?shù)組
            */
          function getSplitItemsMinTop(
            splitElementItems: HTMLElement[]
          ): number | undefined {
            // 獲取元素中最小top值作為基準(zhǔn)進(jìn)行修正
            let minTop: number | undefined;
            let minElement: HTMLElement | undefined;
            splitElementItems.forEach((splitElement) => {
              let top = splitElement.getBoundingClientRect().top;
              if (minTop) {
                minTop = top < minTop ? top : minTop;
                minElement = top < minTop ? splitElement : minElement;
              } else {
                minTop = top;
                minElement = splitElement;
              }
            });
          
            // 修正當(dāng)前節(jié)點(diǎn)及其前面同層級(jí)節(jié)點(diǎn)的margin值
            if (minTop && minElement) {
              const previousElement = splitElementItems[splitElementItems.length - 1].previousElementSibling as HTMLElement;
              minTop -= getMarinTopNum(previousElement, minElement);
            }
            return minTop;
          }
          
          /**
            * 通過(guò)前一個(gè)兄弟元素和元素自身的位置確認(rèn)一個(gè)距離頂部高度修正值
            * @param previousElement 前一個(gè)兄弟元素
            * @param curElement 當(dāng)前元素
            */
          function getMarinTopNum(previousElement: HTMLElement, curElement: HTMLElement): number {
            let preMarginNum = 0;
            let curMarginNum = 0;
            if (previousElement) {
              // 獲取外聯(lián)樣式需要getComputedStyle(), 直接.style時(shí)對(duì)象的值都為空
              const previousMarginBottom = window.getComputedStyle(previousElement).marginBottom;
              preMarginNum = previousMarginBottom ? Number(previousMarginBottom.replace('px', '')) : 0;
            }
            const marginTop = window.getComputedStyle(curElement).marginTop;
            curMarginNum = marginTop ? Number(marginTop.replace('px', '')) : 0;
            return preMarginNum > curMarginNum ? preMarginNum : curMarginNum;
          }

          以上純?cè)瓌?chuàng)!歡迎加關(guān)注、加收藏、點(diǎn)贊、轉(zhuǎn)發(fā)、分享(代碼閑聊站)~


          主站蜘蛛池模板: 亚洲国产成人久久综合一区77| 国产精品一区二区三区免费 | 成人免费一区二区三区在线观看| 无码AV动漫精品一区二区免费| 国产a∨精品一区二区三区不卡| 国产SUV精品一区二区88| 久久久久国产一区二区三区| 日韩精品一区二区三区老鸦窝| 无码精品黑人一区二区三区| 一区二区三区日本视频| 日本免费一区尤物| 亚洲一区二区三区深夜天堂| 国产在线一区二区三区| 亚洲爽爽一区二区三区| 精品一区二区久久久久久久网精| 亚洲国产精品自在线一区二区| 中文字幕一区二区区免| 国产一区二区三区电影| 日本国产一区二区三区在线观看| 久久久精品人妻一区亚美研究所 | 国产人妖视频一区二区| 美女视频一区二区| 日本福利一区二区| 亚洲av色香蕉一区二区三区蜜桃| 午夜福利一区二区三区在线观看| 波多野结衣的AV一区二区三区| 国产一区二区三区无码免费| 99国产精品欧美一区二区三区| 亚洲欧美成人一区二区三区| 亚洲天堂一区二区三区四区| 麻豆一区二区在我观看| 久久se精品一区二区国产| 亚洲AV无码一区二区二三区软件| 国产色情一区二区三区在线播放 | 亚洲国产欧美一区二区三区| 亚洲一区精品视频在线| 亚洲视频免费一区| 蜜桃视频一区二区三区在线观看| 乱子伦一区二区三区| 91精品一区二区综合在线| tom影院亚洲国产一区二区|