整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          好程序員web前端教程分享默認行為和拖拽思路

          程序員web前端分享默認行為和拖拽思路,默認行為:什么是默認行為:默認行為就是瀏覽器自己觸發的事件。比如:a鏈接的跳轉,form提交時的跳轉,鼠標右鍵跳轉;

          oncontexmenu當點擊右鍵菜單的時候;

          return false

          阻止默認行為

          if(e.preventDefault) {

          e.preventDefault();

          }else {

          window.event.returnValue = false;

          }

          事件移除。document.onmouseover=null;

          拖拽

          拖拽事件:

          onmousedown onmousemove onmouseup

          拖拽思路:

          1.給目標元素添加onmousedown事件,拖拽的前提是在目標元素按下鼠標左鍵

          2.當onmousedown發生以后,此刻給document添加onmousemove事件,意味著此刻鼠標在網頁的移動都將改變目標元素的位置

          3.在onmousemove事件中,設定目標元素的left和top,

          公式

          目標元素的left = 鼠標的clientX – (鼠標和元素的橫坐標差,即offsetX)

          目標元素的top = 鼠標的clientY– (鼠標和元素的縱坐標差,即offsetY)

          4.當onmousedown發生以后,此刻給document添加onmouseup事件,意味著此刻鼠標在網頁的任意位置松開鼠標,都會放棄拖拽的效果

          在onmouseup事件中,取消document的onmousemove事件即可。

          事件觸發階段主要由于事件流:DOM0級事件處理階段和DOM2級事件處理;

          DOM0級事件處理,是一種賦值方式,是被所有瀏覽器所支持的,簡單易懂容易操作;

          DOM2級事件處理是所有DOM節點中的方法,可以重復綁定,但是瀏覽器兼容存在問題;

          非IE下:(這里的事件名不帶on),第三個參數表示是在捕獲階段還是冒泡階段。可以重復綁定事件,執行順序按照綁定順序來執行。

          oDiv.addEventListener('click',chick,false);

          oDiv.removeEventListener('click',chick ,false);

          IE下:

          只有冒泡階段,所以沒有第三個參數;(這里的事件名需要加on)

          oDiv.attachEvent();

          oDiv.detachEvent() ;

          兼容問題解決:

          var EventUtil={

          addHandler:function(DOM,EventType,fn){

          if(DOM.addEventListener){

          DOM.addEventListener(EventType,fn,false);

          }else if(DOM.attachEvent){

          DOM.attachEvent('on'+EventType,fn)

          }else{

          DOM['on'+EventType]=fn

          }

          },

          removeHandler:function(DOM,EventType,fn){

          if(DOM.removeEventListener){

          DOM.removeEventListener(EventType,fn,false)

          }else if(DOM.detachEvent){

          DOM.detachEvent('on'+EventType,fn)

          }else{

          DOM['on'+EventType]=null;

          }

          }

          }

          寫一個完美拖拽的案例:

          <!DOCTYPE html>

          <html>

          <title>完美拖拽</title>

          <style type="text/css">

          html,body{overflow:hidden;}

          body,div,h2,p{margin:0;padding:0;}

          body{color:#fff;background:#000;font:12px/2 Arial;}

          p{padding:0 10px;margin-top:10px;}

          span{color:#ff0;padding-left:5px;}

          #box{position:absolute;width:300px;height:150px;background:#333;border:2px solid #ccc;top:50%;left:50%;margin:-75px 0 0 -150px;}

          #box h2{height:25px;cursor:move;background:#222;border-bottom:2px solid #ccc;text-align:right;padding:0 10px;}

          #box h2 a{color:#fff;font:12px/25px Arial;text-decoration:none;outline:none;}

          </style>

          <script type="text/javascript">

          window.onload=function(){

          var positionArray = [];

          var box = document.getElementById("box");

          box.onmousedown = function(evt){

          positionArray = [];

          var x = evt.offsetX;

          var y = evt.offsetY;

          document.onmousemove = function(evt){

          box.style.left = evt.clientX - x + "px";

          box.style.top = evt.clientY - y + "px";

          console.log({left:box.offsetLeft, top: box.offsetTop})

          positionArray.push({left:box.offsetLeft, top: box.offsetTop});

          }

          }

          box.onmouseup = function(){

          document.onmousemove = null;

          }

          box.children[0].firstChild.onmousedown = function(evt){

          evt.stopPropagation();

          }

          box.children[0].firstChild.onclick = function(){

          console.log(positionArray.length);

          var index = positionArray.length-1;

          var timer = setInterval(function(){

          if(index < 0) {

          clearInterval(timer);

          return;

          }

          box.style.left = positionArray[index--].left+"px";

          box.style.top = positionArray[index--].top+"px";

          },30);

          }

          };

          </script>

          </head>

          <body>

          <div id="box" style="margin-left: 0px; margin-top: 0px; left: 533px; top: 231px;">

          <h2><a href="javascript:;">點擊回放拖動軌跡</a></h2>

          <p><strong>Drag:</strong><span>false</span></p>

          <p><strong>offsetTop:</strong><span>231</span></p>

          <p><strong>offsetLeft:</strong><span>533</span></p>

          </div>

          </body></html>

          最近再做一個需求,需要對網頁生成預覽圖,如下圖


          但是網頁千千萬,總不能一個個打開,截圖吧;于是想著能不能使用代碼來實現網頁的截圖。其實要實現這個功能,無非就是要么實現一個仿真瀏覽器,要么調用系統瀏覽器,再進行截圖操作。

          代碼實現

          1、啟用線程Thread

          •  void startPrintScreen(ScreenShotParam requestParam) { Thread thread = new Thread(new ParameterizedThreadStart(do_PrintScreen)); thread.SetApartmentState(ApartmentState.STA); thread.Start(requestParam); if (requestParam.Wait) { thread.Join(); FileInfo result = new FileInfo(requestParam.SavePath); long minSize = 1 * 1024;// 太小可能是空白圖,重抓 int maxRepeat = 2;  while ((!result.Exists || result.Length <= minSize) && maxRepeat > 0) { thread = new Thread(new ParameterizedThreadStart(do_PrintScreen)); thread.SetApartmentState(ApartmentState.STA); thread.Start(requestParam); thread.Join(); maxRepeat--; } } }

            2、模擬瀏覽器WebBrowser

            •  void do_PrintScreen(object param) { try { ScreenShotParam screenShotParam = (ScreenShotParam)param; string requestUrl = screenShotParam.Url; string savePath = screenShotParam.SavePath; WebBrowser wb = new WebBrowser(); wb.ScrollBarsEnabled = false; wb.ScriptErrorsSuppressed = true; wb.Navigate(requestUrl); logger.Debug("wb.Navigate"); DateTime startTime = DateTime.Now; TimeSpan waitTime = new TimeSpan(0, 0, 0, 10, 0);// 10 second while (wb.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); if (DateTime.Now - startTime > waitTime) { wb.Dispose(); logger.Debug("wb.Dispose() timeout"); return; } }
              wb.Width = screenShotParam.Left + screenShotParam.Width + screenShotParam.Left; // wb.Document.Body.ScrollRectangle.Width (避掉左右側的邊線); wb.Height = screenShotParam.Top + screenShotParam.Height; // wb.Document.Body.ScrollRectangle.Height; wb.ScrollBarsEnabled = false; wb.Document.Body.Style = "overflow:hidden";//hide scroll bar var doc = (wb.Document.DomDocument) as mshtml.IHTMLDocument2; var style = doc.createStyleSheet("", 0); style.cssText = @"img { border-style: none; }";
              Bitmap bitmap = new Bitmap(wb.Width, wb.Height); wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height)); wb.Dispose(); logger.Debug("wb.Dispose()");
              bitmap = CutImage(bitmap, new Rectangle(screenShotParam.Left, screenShotParam.Top, screenShotParam.Width, screenShotParam.Height)); bool needResize = screenShotParam.Width > screenShotParam.ResizeMaxWidth || screenShotParam.Height > screenShotParam.ResizeMaxWidth; if (needResize) { double greaterLength = bitmap.Width > bitmap.Height ? bitmap.Width : bitmap.Height; double ratio = screenShotParam.ResizeMaxWidth / greaterLength; bitmap = Resize(bitmap, ratio); }
              bitmap.Save(savePath, System.Drawing.Imaging.ImageFormat.Gif); bitmap.Dispose(); logger.Debug("bitmap.Dispose();"); logger.Debug("finish");
              } catch (Exception ex) { logger.Info($"exception: {ex.Message}"); } }

              3、截圖操作

              •  private static Bitmap CutImage(Bitmap source, Rectangle section) { // An empty bitmap which will hold the cropped image Bitmap bmp = new Bitmap(section.Width, section.Height); //using (Bitmap bmp = new Bitmap(section.Width, section.Height)) { Graphics g = Graphics.FromImage(bmp);
                // Draw the given area (section) of the source image // at location 0,0 on the empty bitmap (bmp) g.DrawImage(source, 0, 0, section, GraphicsUnit.Pixel);
                return bmp; } }
                private static Bitmap Resize(Bitmap originImage, Double times) { int width = Convert.ToInt32(originImage.Width * times); int height = Convert.ToInt32(originImage.Height * times);
                return ResizeProcess(originImage, originImage.Width, originImage.Height, width, height); }

                完整代碼


                •  public static string ScreenShotAndSaveAmazonS3(string account, string locale, Guid rule_ID, Guid template_ID) {  //新的Template var url = string.Format("https://xxxx/public/previewtemplate?showTemplateName=0&locale={0}&inputTemplateId={1}&inputThemeId=&Account={2}", locale, template_ID, account ); 
                  var tempPath = Tools.GetAppSetting("TempPath");
                  //路徑準備 var userPath = AmazonS3.GetS3UploadDirectory(account, locale, AmazonS3.S3SubFolder.Template); var fileName = string.Format("{0}.gif", template_ID); var fullFilePath = Path.Combine(userPath.LocalDirectoryPath, fileName); logger.Debug("userPath: {0}, fileName: {1}, fullFilePath: {2}, url:{3}", userPath, fileName, fullFilePath, url); //開始截圖,並暫存在本機 var screen = new Screen(); screen.ScreenShot(url, fullFilePath);
                  //將截圖,儲存到 Amazon S3 //var previewImageUrl = AmazonS3.UploadFile(fullFilePath, userPath.RemotePath + fileName);
                  return string.Empty; }


                  • using System;using System.Collections.Generic;using System.Drawing;using System.IO;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Windows.Forms;
                    namespace PrintScreen.Common{ public class Screen { protected static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
                    public void ScreenShot(string url, string path , int width = 400, int height = 300 , int left = 50, int top = 50 , int resizeMaxWidth = 200, int wait = 1) { if (!string.IsOrEmpty(url) && !string.IsOrEmpty(path)) { ScreenShotParam requestParam = new ScreenShotParam { Url = url, SavePath = path, Width = width, Height = height, Left = left, Top = top, ResizeMaxWidth = resizeMaxWidth, Wait = wait != 0 }; startPrintScreen(requestParam); } }
                    void startPrintScreen(ScreenShotParam requestParam) { Thread thread = new Thread(new ParameterizedThreadStart(do_PrintScreen)); thread.SetApartmentState(ApartmentState.STA); thread.Start(requestParam); if (requestParam.Wait) { thread.Join(); FileInfo result = new FileInfo(requestParam.SavePath); long minSize = 1 * 1024;// 太小可能是空白圖,重抓 int maxRepeat = 2; while ((!result.Exists || result.Length <= minSize) && maxRepeat > 0) { thread = new Thread(new ParameterizedThreadStart(do_PrintScreen)); thread.SetApartmentState(ApartmentState.STA); thread.Start(requestParam); thread.Join(); maxRepeat--; } } }
                    void do_PrintScreen(object param) { try { ScreenShotParam screenShotParam = (ScreenShotParam)param; string requestUrl = screenShotParam.Url; string savePath = screenShotParam.SavePath; WebBrowser wb = new WebBrowser(); wb.ScrollBarsEnabled = false; wb.ScriptErrorsSuppressed = true; wb.Navigate(requestUrl); logger.Debug("wb.Navigate"); DateTime startTime = DateTime.Now; TimeSpan waitTime = new TimeSpan(0, 0, 0, 10, 0);// 10 second while (wb.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); if (DateTime.Now - startTime > waitTime) { wb.Dispose(); logger.Debug("wb.Dispose() timeout"); return; } }
                    wb.Width = screenShotParam.Left + screenShotParam.Width + screenShotParam.Left; // wb.Document.Body.ScrollRectangle.Width (避掉左右側的邊線); wb.Height = screenShotParam.Top + screenShotParam.Height; // wb.Document.Body.ScrollRectangle.Height; wb.ScrollBarsEnabled = false; wb.Document.Body.Style = "overflow:hidden";//hide scroll bar var doc = (wb.Document.DomDocument) as mshtml.IHTMLDocument2; var style = doc.createStyleSheet("", 0); style.cssText = @"img { border-style: none; }";
                    Bitmap bitmap = new Bitmap(wb.Width, wb.Height); wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height)); wb.Dispose(); logger.Debug("wb.Dispose()");
                    bitmap = CutImage(bitmap, new Rectangle(screenShotParam.Left, screenShotParam.Top, screenShotParam.Width, screenShotParam.Height)); bool needResize = screenShotParam.Width > screenShotParam.ResizeMaxWidth || screenShotParam.Height > screenShotParam.ResizeMaxWidth; if (needResize) { double greaterLength = bitmap.Width > bitmap.Height ? bitmap.Width : bitmap.Height; double ratio = screenShotParam.ResizeMaxWidth / greaterLength; bitmap = Resize(bitmap, ratio); }
                    bitmap.Save(savePath, System.Drawing.Imaging.ImageFormat.Gif); bitmap.Dispose(); logger.Debug("bitmap.Dispose();"); logger.Debug("finish");
                    } catch (Exception ex) { logger.Info($"exception: {ex.Message}"); } }
                    private static Bitmap CutImage(Bitmap source, Rectangle section) { // An empty bitmap which will hold the cropped image Bitmap bmp = new Bitmap(section.Width, section.Height); //using (Bitmap bmp = new Bitmap(section.Width, section.Height)) { Graphics g = Graphics.FromImage(bmp);
                    // Draw the given area (section) of the source image // at location 0,0 on the empty bitmap (bmp) g.DrawImage(source, 0, 0, section, GraphicsUnit.Pixel);
                    return bmp; } }
                    private static Bitmap Resize(Bitmap originImage, Double times) { int width = Convert.ToInt32(originImage.Width * times); int height = Convert.ToInt32(originImage.Height * times);
                    return ResizeProcess(originImage, originImage.Width, originImage.Height, width, height); }
                    private static Bitmap ResizeProcess(Bitmap originImage, int oriwidth, int oriheight, int width, int height) { Bitmap resizedbitmap = new Bitmap(width, height); //using (Bitmap resizedbitmap = new Bitmap(width, height)) { Graphics g = Graphics.FromImage(resizedbitmap); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.Clear(Color.Transparent); g.DrawImage(originImage, new Rectangle(0, 0, width, height), new Rectangle(0, 0, oriwidth, oriheight), GraphicsUnit.Pixel); return resizedbitmap; } }
                    }
                    class ScreenShotParam { public string Url { get; set; } public string SavePath { get; set; } public int Width { get; set; } public int Height { get; set; } public int Left { get; set; } public int Top { get; set; } /// <summary> /// 長邊縮到指定長度 /// </summary> public int ResizeMaxWidth { get; set; } public bool Wait { get; set; } }
                    }

                    效果

                    完成,達到預期的效果。

          在前面:

          本文將和各位老鐵一起探索如何使用CSS變量來降低復雜布局和交互的代碼編寫難度,并使其更易于維護。這里即將分享兩篇該系列的文章,本篇是分享css變量的探索應用的各種用例。

          進入文章前,我們先看下圖,一張網站常用的響應式信息圖表布局圖,當然實現的方式很多,如果我告訴您一個CSS聲明會在以下圖像中對寬屏情況(左測)和第二個(右測)之間產生差異,用一個CSS聲明實現在寬屏幕的情況下對奇數項和偶數項進行區分,從而來實現下面效果,你會不會覺得有點驚喜?

          或者僅僅一個CSS聲明就能區別下面的壓縮和擴展的情況?

          有點意思吧,接下來,我們就一起探索CSS變量在復雜布局和交互的一些小運用。關于CSS變量是什么以及如何開始使用它們的文章已經很多了,所以我們不會在這里深入討論。我們將直接深入了解CSS變量為什么對實現這些情況和其他情況有用,然后我們將進一步詳細解釋如何實現各種情況。我們將從頭編寫一個實際示例,一步一步地編寫,最后,您將通過使用相同技術的更多演示獲得一些引人注目的東西。所以讓我們開始吧!(ps:本文樣式都是scss編寫)

          為什么CSS變量很有用

          對我而言,CSS變量的最大優點是它們以邏輯,數學和輕松的方式為事物的樣式打開了大門。看下面這個陰陽圖,其實是使用loader元素的兩個偽元素創建兩個半部分

          旋轉?符號,兩個半的大小逐漸增大和減小。我們使用相同的 background , border-color , transform-origin 和 animation-delay 值兩半。這些值都取決于 --i 最初設置為 0 兩半(偽元素)的開關變量,但隨后我們將其更改 1 為后半部分( :after 偽元素),從而動態修改所有這些屬性的計算值。

          如果沒有CSS變量,我們將不得不再次在:after偽元素上設置所有這些屬性(border-color、transform-origin、background、anima -delay),并可能出現一些錯誤,甚至忘記設置其中一些屬性。

          一般情況下切換的工作原理

          一、在零和非零值之間切換

          在陰陽加載器的特定情況下,我們在兩半(偽元素)之間改變的所有屬性對于開關的一個狀態變為零值而對于另一個狀態變為非零值。

          如果我們希望當開關關閉( --i: 0 )時我們的值為零,而當開關打開()時我們的值為非零 --i:1,那么我們將它與開關值( var(--i) )相乘。這樣,如果我們的非零值應該是 30deg ,我們有一個角度值,我們有:

          • 當開關 關閉
          • ( --i: 0 )時, calc(var(--i)*30deg) 計算到 0*30deg = 0deg
          • 當開關 打開
          • ( --i: 1 )時, calc(var(--i)*30deg) 計算到 1*30deg = 30deg

          您可以看到以下所示的概念:

          在零和非零值之間切換(現場演示,由于 calc() 不處理角度值而沒有Edge支持)

          對于裝載機的特定情況下,我們使用HSL值 border-color 和 background-color 。HSL代表色調,飽和度,亮度,并且可以借助于雙錐體(其由粘合在一起的基部的兩個錐體組成)在視覺上最佳地表示。

          色調圍繞著雙色調, 0° 相當于 360° 在兩種情況下都給我們一個紅色

          飽和度從 0% 雙錐的垂直軸到 100% 雙錐面上。當飽和度 0% (在雙錐的垂直軸上)時,色調不再重要;對于同一水平面上的所有色調,我們得到完全相同的灰色。“相同水平面”是指具有相同的亮度,其沿垂直軸雙錐增加,從去 0% 在黑色雙圓錐體的頂點,以 100% 在白色雙圓錐體的頂點。當亮度是 0% 或者 100% ,色調和飽和度都不再重要時 - 我們總是得到黑色亮度值 0% 和白色亮度值 100% 。因為我們只需要黑色和白色我們的?符號,色調和飽和度是不相關的,所以我們清除它們,然后之間進行切換黑色,并白色通過切換之間的亮度 0% 和 100% 。

          .yin-yang {
           &:before, &:after {
           --i: 0;
           /* lightness of border-color when 
           * --i: 0 is (1 - 0)*100% = 1*100% = 100% (white)
           * --i: 1 is (1 - 1)*100% = 0*100% = 0% (black) */
           border: solid $d/6 hsl(0, 0%, calc((1 - var(--i))*100%));
           /* x coordinate of transform-origin when 
           * --i: 0 is 0*100% = 0% (left) 
           * --i: 1 is 1*100% = 100% (right) */
           transform-origin: calc(var(--i)*100%) 50%;
           /* lightness of background-color when 
           * --i: 0 is 0*100% = 0% (black) 
           * --i: 1 is 1*100% = 100% (white) */
           background: hsl(0, 0%, calc(var(--i)*100%));
           /* animation-delay when
           * --i: 0 is 0*-$t = 0s 
           * --i: 1 is 1*-$t = -$t */
           animation: s $t ease-in-out calc(var(--i)*#{-$t}) infinite alternate;
           }
           &:after { --i: 1 }
          }
          
          

          但是,如果我們想要在開關關閉( --i: 0 )時具有非零值而在開關打開時具有另一個不同的非零值( --i: 1 )呢?

          一、在兩個非零值之間切換

          假設我們希望一個元素在開關關閉時具有灰色 background ( #ccc ),在開關打開時 --i: 0

          具有橙色 background ( #f90 )( --i: 1 )。我們要做的第一件事是從十六進制切換到更易于管理的格式,如 rgb() 或 hsl() 。我們可以通過使用諸如Lea Verou的CSS Colors之類的工具或通過DevTools手動完成此操作。如果我們 background 在元素上有一個集合,我們可以通過 Shift 按住鍵來循環瀏覽格式,同時單擊DevTools中值前面的正方形(或圓圈)。這適用于Chrome和Firefox,但它似乎不適用于Edge。

          更妙的是,如果我們使用無禮的話,我們可以提取成分 red() / green() / blue()hue() /

          saturation() / lightness() 函數。雖然 rgb() 可能是更為人所知的格式,但我更傾向于 hsl()因為我發現它更直觀,而且通過查看代碼,我更容易了解視覺效果。因此,我們使用以下函數提取

          hsl() 兩個值的等價物的三個組成部分( $c0: #ccc 當開關關閉 $c1: #f90 時和開關打開時):

          $c0: #ccc;
          $c1: #f90;
          $h0: round(hue($c0)/1deg);
          $s0: round(saturation($c0));
          $l0: round(lightness($c0));
          $h1: round(hue($c1)/1deg);
          $s1: round(saturation($c1));
          $l1: round(lightness($c1))
          
          

          請注意,我們已經四舍五入的結果hue(),saturation()并lightness()作為他們可能返回大量的小數,我們要保持我們生成的代碼干凈。我們還將hue()函數的結果除以1deg,因為在這種情況下返回值是度值,而Edge僅支持CSS hsl()函數內的無單位值。通常,在使用Sass時,我們可以使用度數值,而不僅僅是hsl()函數內部hue的單位值,因為Sass將其視為Sass hsl()函數,它被編譯為hsl()具有無單位色調的CSS 函數。但是在這里,我們內部有一個動態CSS變量,因此Sass將此函數視為CSShsl() 沒有編譯成其他任何東西的函數,因此,如果hue有一個單元,則不會從生成的CSS中刪除它。

          現在我們有:

          • 如果開關關閉(--i: 0),我們background是 hsl($h0, $s0, $l0)
          • 如果開關打開(--i: 1),我們background是 hsl($h1, $s1, $l1)

          我們可以將我們的兩個背景寫成:

          • 如果開關關閉( --i: 0 ), hsl(1*$h0 + 0*$h1, 1*$s0 + 0*$s1, 1*$l0 + 1*$l1)
          • 如果開關打開( --i: 1 ), hsl(0*$h0 + 1*$h1, 0*$s0 + 1*$s1, 0*$l0 + 1*$l1)

          在這里,我們記--j的互補值--i(當--i是0,--j是1,當--i是1,--j是0)。

          上述公式適用于在任意兩個HSL值之間切換。但是,在這種特殊情況下,我們可以簡化它,因為當開關關閉時我們有一個純灰色(--i: 0)。

          考慮到RGB模型,純灰度值具有相等的紅色,綠色和藍色值。 當考慮HSL模型時,色調是無關緊要的(我們的灰色看起來對于所有色調都是相同的),飽和度總是0%只有亮度很重要,決定了我們的灰色是多么亮或暗。 在這種情況下,我們可以始終保持非灰色值的色調(我們對“on”情況所具有的色調$h1)。

          由于任何灰度值(我們對“關閉”情況所具有的)的飽和度 $s0始終是0%,將其乘以0或者1總是給出我們0%。因此,考慮到var(--j)*#{$s0}我們的公式中的術語總是如此0%,我們可以放棄它,我們的飽和公式減少到“on”情況$s1和switch變量飽和之間的乘積--i。 這使得輕盈成為我們仍然需要應用完整配方的唯一組成部分

          --j: calc(1 - var(--i));
          background: hsl($h1, 
           calc(var(--i)*#{$s1}), 
           calc(var(--j)*#{$l0} + var(--i)*#{d1l}))
          
          

          以上內容可在此演示中進行測試。 類似地,假設我們想要font-size一些文本2rem在我們的開關關閉(--i: 0)和10vw開關打開(--i: 1)時。應用相同的方法,我們有:

          font-size: calc((1 - var(--i))*2rem + var(--i)*10vw)
          
          

          觸發切換

          一、基于元素的切換

          這意味著某些元件和其他元件的開關關閉。例如,這可以通過奇偶校驗來確定。假設我們希望所有偶數元素都旋轉并且具有橙色background而不是初始灰色元素

          .box {
           --i: 0;
           --j: calc(1 - var(--i));
           transform: rotate(calc(var(--i)*30deg));
           background: hsl($h1, 
           calc(var(--i)*#{$s1}), 
           calc(var(--j)*#{$l0} + var(--i)*#{$l1}));
           
           &:nth-child(2n) { --i: 1 }
          }
          
          

          由項目奇偶校驗觸發的切換(實時演示,由于calc()不適用于角度值而在Edge中不能完全正常工作)

          在奇偶校驗的情況下,我們為每隔一個項目(:nth-child(2n))打開開關,但我們也可以為前七個項目(:nth-child(7n)),前兩個項目(:nth-child(-n + 2)),為除了第一個和最后兩個(:nth-child(n + 3):nth-last-child(n + 3))之外的所有項目打開它。我們也可以僅針對標題或僅針對具有特定屬性的元素進行翻轉。

          二、狀態切換

          這意味著當元素本身(或父元素或其先前的兄弟元素之一)處于一種狀態時關閉開關,而當它是另一種狀態時關閉。在上一節的交互式示例中,在檢查或取消選中元素之前的復選框時,交換機被翻轉。我們還可以使用白色鏈接,在聚焦或懸停時可以放大并變成橙色:

          $c: #f90;
          $h: round(hue($c)/1deg);
          $s: round(saturation($c));
          $l: round(lightness($c));
          a {
           --i: 0;
           transform: scale(calc(1 + var(--i)*.25));
           color: hsl($h, $s, calc(var(--i)*#{$l} + (1 - var(--i))*100%)); 
           &:focus, &:hover { --i: 1 }
          }
          
          

          因為white任何hsl()具有亮度100%(色調和飽和度都無關緊要)的值,我們可以通過始終保持:focus/ :hover狀態的色調和飽和度并且僅改變亮度來簡化事物。

          由狀態變化觸發的切換(現場演示,由于功能calc()內部不支持的值,Edge中功能不全scale())

          三、基于媒體查詢的切換

          另一種可能性是切換由媒體查詢觸發,例如,當方向改變時或從一個視口范圍轉到另一個視口范圍時。 比方說,我們有white一個標題font-size的1rem最高320px,但隨后變為橙色($c)和font-size變5vw,并開始與視縮放width。

          h5 {
           --i: 0;
           color: hsl($h, $s, calc(var(--i)*#{$l} + (1 - var(--i))*100%));
           font-size: calc(var(--i)*5vw + (1 - var(--i))*1rem);
           @media (min-width: 320px) { --i: 1 }
          }
          
          

          從頭開始編寫一個更復雜的例子-搜索

          我們在這里剖析的例子是本文開頭展示的擴展搜索

          ps:從可用性的角度來看,在網站上設置這樣的搜索框可能不是最好的主意,因為人們通常期望搜索框后面的按鈕觸發搜索,而不是關閉搜索欄,但它仍然是一個有趣的編碼練習,這就是為什么我選擇在這里剖析它。

          首先,我的想法是僅使用表單元素來完成它。

          因此,HTML結構如下所示:

          <input id='search-btn' type='checkbox'/>
          <label for='search-btn'>Show search bar</label>
          <input id='search-bar' type='text' placeholder='Search...'/>
          
          

          我們在這里做的最初是隱藏文本input,然后在選中復選框之前將其顯示出來 - 讓我們深入了解它是如何工作的! 首先,我們使用基本重置并flex在我們input和label元素的容器上設置布局。在我們的例子中,這個容器是body,但也可能是另一個元素。我們也絕對定位復選框并將其移出視線(視口外)。

          *, :before, :after {
           box-sizing: border-box;
           margin: 0;
           padding: 0;
           font: inherit
          }
          html { overflow-x: hidden }
          body {
           display: flex;
           align-items: center;
           justify-content: center;
           margin: 0 auto;
           min-width: 400px;
           min-height: 100vh;
           background: #252525
          }
          [id='search-btn'] {
           position: absolute;
           left: -100vh
          }
          
          

          我們把復選框label變成一個大的綠色圓形按鈕,并使用一個大的負數值移動它的文本內容的視線text-indent和overflow: hidden。

          $btn-d: 5em; /* 同上 */[for='search-btn'] {
           overflow: hidden;
           width: $btn-d;
           height: $btn-d;
           border-radius: 50%;
           box-shadow: 0 0 1.5em rgba(#000, .4);
           background: #d9eb52;
           text-indent: -100vw;
           cursor: pointer;
          }
          
          

          接下來,我們通過以下方式修改實際搜索欄:

          • 給它明確的維度
          • 提供 background 正常狀態
          • background 為其聚焦狀態定義不同的光暈
          • 使用 border-radius 相當于其一半的左側角落 height
          • 清理占位符一點
          $btn-d: 5em;
          $bar-w: 4*$btn-d;
          $bar-h: .65*$btn-d;
          $bar-r: .5*$bar-h;
          $bar-c: #ffeacc;/* 同上 */
          [id='search-bar'] {
           border: none;
           padding: 0 1em;
           width: $bar-w;
           height: $bar-h;
           border-radius: $bar-r 0 0 $bar-r;
           background: #3f324d;
           color: #fff;
           font: 1em century gothic, verdana, arial, sans-serif;
           &::placeholder {
           opacity: .5;
           color: inherit;
           font-size: .875em;
           letter-spacing: 1px;
           text-shadow: 0 0 1px, 0 0 2px
           }	
           &:focus {
           outline: none;
           box-shadow: 0 0 1.5em $bar-c, 0 1.25em 1.5em rgba(#000, .2);
           background: $bar-c;
           color: #000;
           }
          }
          復制代碼
          

          此時,搜索欄的右邊緣與按鈕的左邊緣重合。但是,我們想要一些重疊 - 假設重疊使得搜索欄的右邊緣與按鈕的垂直中線重合。鑒于我們align-items: center在容器上有一個flexbox布局(body在我們的例子中),由我們的兩個項目組成的組件(條和按鈕)保持水平中間對齊,即使我們設置margin一個或另一個或在這兩個項目之間。(在最左邊的項目的左側或最右邊的項目的右側是一個不同的故事,但我們現在不會進入那個。)

          這是.5*$btn-d半個按鈕直徑的重疊,相當于按鈕的半徑。我們margin-right在欄上將其設為負數。我們還調整padding條形圖的右側,以便我們補償重疊:

          $btn-d: 5em;
          $btn-r: .5*$btn-d;
          /* 同上 */
          [id='search-bar'] {
           /* 同上 */
           margin-right: -$btn-r;
           padding: 0 calc(#{$btn-r} + 1em) 0 1em;
          }
          
          

          除了條形按照DOM順序中的按鈕,所以它放在它的頂部,當我們真正想要按鈕在頂部。

          幸運的是,這有一個簡單的解決方案(至少現在 - 以后還不夠,但讓我們一次處理一個問題)。

          [for='search-btn'] {
           /* 同上 */
           position: relative;
          }
          

          在這種狀態下,條形和按鈕組件的總寬度是條形寬度$bar-w加上按鈕的半徑$btn-r(按鈕直徑的一半$btn-d),因為按鈕的一半重疊。在折疊狀態下,組件的總寬度就是按鈕直徑$btn-d。

          由于我們希望在從展開狀態到折疊狀態時保持相同的中心軸,我們需要將按鈕向左移動擴展狀態(.5*($bar-w + $btn-r))減去按鈕半徑($btn-r)的組件寬度的一半。 我們稱之為這種轉變$x,我們在按鈕上使用減號(因為我們將按鈕向左移動,左邊是x軸的負方向)。由于我們希望條形圖折疊到按鈕中,我們$x在它上面設置相同的偏移,但是在正方向上(因為我們將條形圖移動到右邊的 x軸)。 當未選中復選框時,我們處于折疊狀態,而當未選中復選框時,我們處于展開狀態。這意味著transform當沒有選中復選框時,我們的欄和按鈕會被CSS移動,并且我們當前將它們置于其中(沒有transform)。 為了做到這一點,我們--i在復選框后面的元素上設置了一個變量- 按鈕(使用label復選框創建)和搜索欄。此變量0處于折疊狀態(當兩個元素都移位且未選中復選框時)并1處于展開狀態(當我們的條和按鈕位于它們當前占據的位置時,沒有移位,并且復選框被選中)

          $x: .5*($bar-w + $btn-r) - $btn-r;
          [id='search-btn'] {
           position: absolute;
           left: -100vw;	
           ~ * {
           --i: 0;
           --j: calc(1 - var(--i)) /* 1 when --i is 0, 0 when --i is 1 */
           }
           &:checked ~ * { --i: 1 }
          }
          [for='search-btn'] {
           /*同之前 */
           transform: translate(calc(var(--j)*#{-$x}));
          }
          [id='search-bar'] {
           /*同之前 */
           transform: translate(calc(var(--j)*#{$x}));
          }
          
          

          我們現在有互動的東西!

          單擊該按鈕可切換復選框狀態(因為該按鈕已使用 label 復選框創建)。

          除了現在按鈕有點難以點擊,因為它再次位于文本輸入下(因為我們在條上設置了 transform.

          并建立了堆疊上下文)。修復非常簡單 - 我們需要 z-index 在按鈕上添加一個按鈕,然后將其移動到條形圖上方。

          但是我們還有另一個更大的問題:我們可以看到右側按鈕下方的欄桿。為了解決這個問題,我們在欄上設置clip-path了一個inset()值。這指定了一個剪切矩形,借助于元素頂部,右側,底部和左側邊緣的距離border-box。剪切矩形之外的所有內容都會被剪切掉,只顯示內部的內容

          在上圖中,每個距離都從邊框的邊緣向內移動。在這種情況下,他們是積極的。但它們也可以向外移動,在這種情況下它們是負的,并且剪切矩形的相應邊緣在元素之外border-box。 起初,您可能認為我們沒有理由這樣做,但在我們的特定情況下,我們會這樣做! 我們希望從top(dt),bottom(db)和left(dl)的距離是負的,并且足夠大以包含在該狀態中box-shadow的元素外部延伸的border-box距離,:focus因為我們不希望它被剪切掉。所以解決方案是創建一個剪切矩形,邊緣在元素之外border-box在這三個方向。 與右邊的距離(dr)是折疊情況下的整個條寬$bar-w減去按鈕半徑$btn-r(未選中復選框--i: 0),并且0在展開的情況下(選中復選框--i: 1)。

          $out-d: -3em;
          [id='search-bar'] {
           /* 同之前 */
           clip-path: inset($out-d calc(var(--j)*#{$bar-w - $btn-r}) $out-d $out-d);
          }
          
          

          我們現在有一個搜索欄和按鈕組件,在單擊按鈕時會展開和折疊。

          由于我們不希望兩個便之間發生突然變化,我們使用 transition :

          [id='search-btn'] {
           /* 同之前 */
           ~ * {
           /* same as before */
           transition: .65s;
           }
          }
          
          

          我們還希望我們的按鈕background在折疊的情況下為綠色(未選中復選框--i: 0),在展開的情況下為粉紅色(選中復選框--i: 1)。為此,我們使用與以前相同的技術:

          [for='search-btn'] {
           /* 同之前 */
           $c0: #d9eb52; // green for collapsed state
           $c1: #dd1d6a; // pink for expanded state
           $h0: round(hue($c0)/1deg);
           $s0: round(saturation($c0));
           $l0: round(lightness($c0));
           $h1: round(hue($c1)/1deg);
           $s1: round(saturation($c1));
           $l1: round(lightness($c1));
           background: hsl(calc(var(--j)*#{$h0} + var(--i)*#{$h1}), 
           calc(var(--j)*#{$s0} + var(--i)*#{$s1}), 
           calc(var(--j)*#{$l0} + var(--i)*#{$l1}));
          }
          
          

          看看效果

          我們仍然需要做的是創建一個圖標,該圖標在折疊狀態的放大鏡和展開狀態的“x”之間變形,以指示關閉動作。我們使用:before和:after偽元素執行此操作。我們首先確定放大鏡的直徑以及圖標線寬度所代表的直徑。

          $ico-d: .5*$bar-h;
          $ico-f: .125;
          $ico-w: $ico-f*$ico-d;
          
          

          我們絕對將偽元素放在按鈕中間,并考慮其尺寸。然后我們把它們變成inherit父母的transition。我們給:beforea background,因為這將是我們的放大鏡的把手,使它成為:after圓形border-radius并給它一個插圖box-shadow。

          [for='search-btn'] {
           /* 同之前 */	
           &:before, &:after {
           position: absolute;
           top: 50%; left: 50%;
           margin: -.5*$ico-d;
           width: $ico-d;
           height: $ico-d;
           transition: inherit;
           content: ''
           }
          	
           &:before {
           margin-top: -.4*$ico-w;
           height: $ico-w;
           background: currentColor
           }
           &:after {
           border-radius: 50%;
           box-shadow: 0 0 0 $ico-w currentColor
           } 
          }
          
          

          我們現在可以在按鈕上看到放大鏡組件,為了使我們的圖標看起來更像放大鏡,我們的translate兩個組件都向外放大了放大鏡直徑的四分之一。這意味著所述手柄平移向右,在正方向X通過軸.25*$ico-d與所述主要部分的左側,在負方向X以相同的軸線.25*$ico-d。 我們還scale手柄(該:before偽元素)水平至其一半width相對于其右邊緣(這意味著一個transform-origin的100%沿X軸)。 我們只希望在折疊狀態下發生這種情況(復選框未選中,--i是0,因此--j是1),因此我們將轉換量乘以--j并用于--j調整比例因子:

          [for='search-btn'] {
           /* 同之前 */
           &:before {
           /* 同之前 */
           height: $ico-w;
           transform: 
           translate(calc(var(--j)*#{.25*$ico-d})) 
           scalex(calc(1 - var(--j)*.5))
           }
           &:after {
           /* same as before */
           transform: translate(calc(var(--j)*#{-.25*$ico-d}))
           } 
          }
          
          

          我們現在處于折疊狀態的放大鏡圖標:

          由于我們希望旋轉兩個圖標組件45deg,我們在按鈕本身上添加此旋轉:

          [for='search-btn'] {
           /* 同之前 */
           transform: translate(calc(var(--j)*#{-$x})) rotate(45deg);
          }
          
          

          這仍然會離開擴展狀態,我們需要將圓形:after偽元素轉換為一條線。我們通過縮放它順著這樣做X軸,將其border-radius從50%到0%。我們使用的縮放系數是$ico-w我們想要獲得的線寬和$ico-d它在折疊狀態下形成的圓的直徑之間的比率。我們稱這個比例$ico-f。 因為我們只希望做這在擴展狀態下,當復選框被選中,并--i是1,我們使這兩個比例因子和border-radius依賴于--i和--j:

          $ico-d: .5*$bar-h;
          $ico-f: .125;
          $ico-w: $ico-f*$ico-d;
          [for='search-btn'] {
           /* 同之前 */	
           &:after{
           /* 同之前 */
           border-radius: calc(var(--j)*50%);
           transform: 
           translate(calc(var(--j)*#{-.25*$ico-d})) 
           scalex(calc(1 - var(--j)*.5))
           }
          }
          
          

          嗯,差不多,但并不完全。縮放也縮水了插圖box-shadow沿X軸,所以我們進行了修復與第二插圖影子,我們(當復選框被選中,并在擴展狀態下只能得到--i是1),因此,它的傳播和α取決于--i:

          $ico-d: .5*$bar-h;
          $ico-f: .125;
          $ico-w: $ico-f*$ico-d;
          [for='search-btn'] {
           /* 同之前 */
           --hsl: 0, 0%, 0%;
           color: HSL(var(--hsl));	
           &:after{
           /* 同之前 */
           box-shadow: 
           inset 0 0 0 $ico-w currentcolor, 
           /* collapsed: not checked, --i is 0, --j is 1
           * spread radius is 0*.5*$ico-d = 0
           * alpha is 0
           * expanded: checked, --i is 1, --j is 0
           * spread radius is 1*.5*$ico-d = .5*$ico-d
           * alpha is 1 */
           inset 0 0 0 calc(var(--i)*#{.5*$ico-d}) HSLA(var(--hsl), var(--i))
           }
          }
          
          

          這給了我們最終的結果! 【本例完整源碼】

          實用案例

          以下是一些使用相同技術的演示。我們不會從頭開始構建這些 - 我們只會介紹它們背后的基本思想

          一、響應橫條

          在這種情況下,我們的實際元素是前面較小的矩形,而后面的數字正方形和較大的矩形分別使用:before和:after偽元素創建。 數字方塊的背景是單獨的,并使用--slist對于每個項目不同的停止列表變量進行設置。

          <p style='--slist: #51a9ad, #438c92'><!-- 1st paragraph text --></p>
          <p style='--slist: #ebb134, #c2912a'><!-- 2nd paragraph text --></p>
          <p style='--slist: #db4453, #a8343f'><!-- 3rd paragraph text --></p>
          <p style='--slist: #7eb138, #6d982d'><!-- 4th paragraph text --></p>
          
          

          影響橫幅樣式的因素是平價,以及我們是處于廣泛,正常還是狹窄的情況。這些給我們的開關變量

          html {
           --narr: 0;
           --comp: calc(1 - var(--narr));
           --wide: 1;	
           @media (max-width: 36em) { --wide: 0 }
           @media (max-width: 20em) { --narr: 1 }
          }
          p {
           --parity: 0; 
           &:nth-child(2n) { --parity: 1 }
          }
          
          

          數字方塊絕對定位,它們的位置取決于奇偶校驗。如果--parity開關關閉(0),則它們在左側。如果它在(1)上,那么它們就在右邊。 一個值left: 0%沿著其父元素的左邊緣與數字方塊的左邊緣left: 100%對齊,而一個值沿著父元素的右邊緣對齊其左邊緣。 為了使數字方塊的右邊緣與其父邊緣的右邊緣對齊,我們需要從前一個100%值中減去自己的寬度。(請記住,%偏移量的值是相對于父級的尺寸。)

          left: calc(var(--parity)*(100% - #{$num-d}))
          
          

          ... $num-d編號方塊的大小在哪里。 在寬屏幕的情況下,我們還向外推送編號1em- 這意味著減去1em我們迄今為止對于奇數項目(--parity關閉開關)1em的偏移量,并添加到目前為止偶數項目的偏移量(--parity開啟時) )。 現在問題是......我們如何切換標志?最簡單的方法是使用的權力-1。遺憾的是,我們在CSS中沒有冪函數(或冪函數運算符),即使它在這種情況下非常有用:

          pow(-1, var(--parity))復制代碼
          

          這意味著我們必須使它與我們所擁有的(加法,減法,乘法和除法)一起工作,這導致了一個奇怪的小公式......但是,嘿,它有效!

          --sign: calc(1 - 2*var(--parity))
          
          left: calc(var(--parity)*(100% - #{$num-d}) - var(--wide)*var(--sign)*1em)
          
          

          我們還width使用這些變量來控制段落,并且max-width我們希望它具有上限并且僅在窄case(--narr: 1)中水平地完全覆蓋其父級:

          width: calc(var(--comp)*80% + var(--narr)*100%);
          max-width: 35em;
          
          

          這font-size也取決于我們是否處于狹窄的情況(--narr: 1)或不是(--narr: 0):

          calc(.5rem + var(--comp)*.5rem + var(--narr)*2vw)
          
          

          ......對于:after偽元素(后面較大的矩形)的水平偏移也是如此,因為它們0在窄情況(--narr: 1)中,而非零偏移,$off-x否則(--narr: 0)

          right: calc(var(--comp)*#{$off-x}); 
          left: calc(var(--comp)*#{$off-x});
          
          

          二、懸停并注重效果

          這個效果是通過一個鏈接元素和它的兩個偽元素在對角:hover和:focus狀態上對角滑動創建的。鏈接的尺寸是固定的,其偽元素也是固定的,設置為它們的父對角線$btn-d(在寬度和高度形成的直角三角形中斜邊計算)水平和父height垂直。

          該:before定位使得它的左下角恰逢其父,而:after被定位為使得其右上角與其父一致。由于兩者都應與height其父級相同,因此通過設置top: 0和解決垂直位置bottom: 0。水平放置的處理方式與前一個示例完全相同,使用--i切換變量來更改兩個偽元素之間的值,并使用--j其互補(calc(1 - var(--i))):

          left: calc(var(--j)*(100% - #{$btn-d}))
          
          

          我們設定transform-origin的:before到它的左下角(0% 100%)和:after其右上角的(100% 0%),再次,與交換機的幫助--i和補充--j

          transform-origin: calc(var(--j)*100%) calc(var(--i)*100%)
          
          

          我們將兩個偽元素旋轉到對角線和水平線之間的角度 $btn-a(也是由高度和寬度形成的三角形計算出來的,作為兩者之間比率的反正切)。通過這種旋轉,水平邊緣沿著對角線相交。 然后我們按照自己的寬度向外移動它們。這意味著我們將為兩者中的每一個使用不同的符號,同樣取決于在:before和之間改變值的switch變量,:after就像前面的橫幅示例一樣:

          transform: rotate($btn-a) translate(calc((1 - 2*var(--i))*100%))
          
          

          在:hover和:focus,這個切換必須回去0。這意味著我們通過互補乘以上面的平移量--q的開關變量--p這是0在正常狀態下和1在:hover或:focus狀態:

          transform: rotate($btn-a) translate(calc(var(--q)*(1 - 2*var(--i))*100%))
          
          

          為了使偽元素在鼠標移出或失焦時以相反的方式滑出(不回溯它們進入的方式),我們將switch變量設置--i為--pfor :before的值,并將值設置--q為for :after,反轉轉換的符號,確保只轉換transform屬性

          三、響應信息

          在這種情況下,我們為每個項目(article元素)都有一個三行,兩列網格,第三行在寬屏幕場景中折疊,第二列在窄屏幕場景中折疊。在寬屏幕場景中,列的寬度取決于奇偶校驗。在窄屏場景中,第一列跨越元素的整個內容框,第二列具有寬度0。我們在列之間也存在差距,但僅限于寬屏場景。

          $col-1-wide: calc(var(--q)*#{$col-a-wide} + var(--p)*#{$col-b-wide});
          $col-2-wide: calc(var(--q)*#{$col-b-wide} + var(--p)*#{$col-a-wide});
          $row-1: calc(var(--i)*#{$row-1-wide} + var(--j)*#{$row-1-norm});
          $row-2: calc(var(--i)*#{$row-2-wide} + var(--j)*#{$row-2-norm});
          $row-3: minmax(0, auto);
          $col-1: calc(var(--i)*#{$col-1-wide} + var(--j)*#{$col-1-norm});
          $col-2: calc(var(--i)*#{$col-2-wide});
          $art-g: calc(var(--i)*#{$art-g-wide});
          html {
           --i: var(--wide, 1); 
           --j: calc(1 - var(--i));
           @media (max-width: $art-w-wide + 2rem) { --wide: 0 }
          }
          article {
           --p: var(--parity, 0);
           --q: calc(1 - var(--p));
           --s: calc(1 - 2*var(--p));
           display: grid;
           grid-template: #{$row-1} #{$row-2} #{$row-3}/ #{$col-1} #{$col-2};
           grid-gap: 0 $art-g;
           grid-auto-flow: column dense;
           &:nth-child(2n) { --parity: 1 }
          }
          
          

          既然我們已經設置了grid-auto-flow: column dense,我們可以在寬屏幕情況下只設置第一級標題來覆蓋整個列(第二個用于奇數項,第一個用于偶數項),并讓第二個級別標題和段落文本填寫第一個可用單元格。

          grid-column: calc(1 + var(--i)*var(--q));
          grid-row: 1/ span calc(1 + 2*var(--i));
          
          

          對于每個項目,一些其他屬性取決于我們是否處于寬屏幕方案中。 在寬屏幕情況下,垂直margin,垂直和水平padding值,box-shadow偏移和模糊都更大:

          $art-mv: calc(var(--i)*#{$art-mv-wide} + var(--j)*#{$art-mv-norm});
          $art-pv: calc(var(--i)*#{$art-pv-wide} + var(--j)*#{$art-p-norm});
          $art-ph: calc(var(--i)*#{$art-ph-wide} + var(--j)*#{$art-p-norm});
          $art-sh: calc(var(--i)*#{$art-sh-wide} + var(--j)*#{$art-sh-norm});
          article {
           margin: $art-mv auto;
           padding: $art-pv $art-ph;
           box-shadow: $art-sh $art-sh calc(3*#{$art-sh}) rgba(#000, .5);
          }
          
          

          我們有一個非零border-width和border-radius寬屏幕的情況

          $art-b: calc(var(--i)*#{$art-b-wide});
          $art-r: calc(var(--i)*#{$art-r-wide});
          article {
           border: solid $art-b transparent;
           border-radius: $art-r;
          }
          
          

          在寬屏幕場景中,我們限制項目width,但100%不管怎樣。

          $art-w: calc(var(--i)*#{$art-w-wide} + var(--j)*#{$art-w-norm});
          article {
           width: $art-w;
          }
          
          

          padding-box 漸變的方向也隨奇偶校驗而變化:

          background: 
           linear-gradient(calc(var(--s)*90deg), #e6e6e6, #ececec) padding-box, 
           linear-gradient(to right bottom, #fff, #c8c8c8) border-box;
          
          

          以類似的方式,margin,border-width,padding,width,border-radius,background梯度方向,font-size或line-height對標題和段落文本還取決于我們是否是在寬屏場景(在第一級標題的情況下border-radius或background梯度方向,也在奇偶校驗)。

          看效果:

          最后

          本篇文章主要介紹了使用CSS變量來驅動布局和交互的切換的策略,其中值得注意的是:只適用于數值 - 長度,百分比,角度,持續時間,頻率,無單位數值等.


          上一篇:HTML 顏色
          下一篇:Html5之Bootstrap框架介紹
          主站蜘蛛池模板: 老熟妇仑乱视频一区二区| 中文人妻无码一区二区三区| 国产视频一区二区在线观看| 美女免费视频一区二区三区| 国产成人午夜精品一区二区三区| 91福利国产在线观一区二区| 亚洲AV无码一区二区一二区| 精品无码综合一区| 香蕉免费看一区二区三区| 国产精品被窝福利一区| 日本精品一区二区在线播放| 91在线精品亚洲一区二区| 福利一区二区三区视频在线观看 | 亚洲中文字幕无码一区| 一区三区三区不卡| 一区在线免费观看| 国产一区中文字幕在线观看| 欧美日韩精品一区二区在线视频 | 中文字幕精品无码一区二区三区 | 国产福利在线观看一区二区| 欧美激情国产精品视频一区二区| 国产福利91精品一区二区| 麻豆天美国产一区在线播放| 91在线一区二区| 亚拍精品一区二区三区| 亚洲中文字幕久久久一区| 亚洲AV无码国产一区二区三区 | 久久无码人妻一区二区三区午夜| 无码人妻一区二区三区免费n鬼沢 无码人妻一区二区三区免费看 | 亚洲精品国产suv一区88| 男插女高潮一区二区| 韩国一区二区三区| 亚洲国产综合精品一区在线播放| 一区二区三区美女视频| 国模无码人体一区二区| 人妻夜夜爽天天爽爽一区| 中文字幕乱码亚洲精品一区| 日韩a无吗一区二区三区| 中文字幕在线视频一区| 久久精品一区二区三区四区| 亚洲一区二区三区不卡在线播放|