Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 免费在线观看你懂的,亚洲九九精品,一级毛片免费毛片一级毛片免费

          整合營銷服務商

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

          免費咨詢熱線:

          第46節 HTML5擴展-Javascript-零點程序員

          內容是《Web前端開發之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學習。

          HTML5規范圍繞著如何使用新增標記定義了大量Javascript API;其中一些API與DOM重疊,定義了瀏覽器應該支持的DOM擴展;

          從HTML4開始,在Web開發領域,有一個非常大的應用,就是濫用class屬性,一方面可以通過它為元素添加樣式,另一方面還可以用它表示元素的語義;于是,開發人員會用大量的Javascript代碼來操作CSS類,比如動態修改類或者搜索文檔中具有給定類或給定的一組類的元素,等等這些操作;為了讓開發人員適應并增加對class屬性的新的認識,HTML5新增了很多API,致力于簡化CSS類的用法;

          getElementsByClassName(names)方法:

          該方法是基于元素class屬性值中的類名來選取成組的文檔元素,可以通過document對象或Element元素調用這個方法;該方法最早出現在第三方Javascript類庫中,是通過既有的DOM功能實現的,而現在,原生的實現具有極大的性能優勢;

          該方法接收一個names參數,即一個包含一個或多個類名的字符串,多個類名使用空格隔開,返回帶有指定類的所有元素的HTMLCollection;

          var elts = document.getElementsByClassName("myclass");
          console.log(elts);  // HTMLCollection
          console.log(elts[0]);  // 第一個元素

          傳入多個類名時,類名的先后順序不重要;如:

          // 取得所有類中同時包括username和current的元素,類名的先后順序無所謂
          var allCurrentUsernames = document.getElementsByClassName("username current");
          console.log(allCurrentUsernames);
          var selected = document.getElementById("mydiv").getElementsByClassName("selected");
          console.log(selected);

          它返回的HTMLCollection集合,可以借用Array的方法,如:

          var elts = document.getElementsByClassName("selected");
          var eltDivs = Array.prototype.filter.call(elts, function(ele){
              return ele.nodeName === 'DIV';
          });
          console.log(eltDivs);  // 返回擁有selected類名的所有div元素

          使用這個方法可以更方便地為帶有某些類的元素添加事件處理程序,從面不必再局限于使用ID或標簽名;

          <style>
          .zr{background-color: rosybrown;}
          @keyframes rotate{
              0%{transform: rotate(0deg);}
              50%{transform: rotate(45deg);}
              100%{transform: rotate(0deg);}
          }
          .animating{
              animation: rotate 2s ease-in-out;
          }
          </style>
          <p class="zr">this is ok</p>
          <!-- 添加若干個class為zr的元素 -->
          <script>
          var elts = document.getElementsByClassName("zr");
          for(var i=0,len=elts.length; i<len; i++){
              elts[i].addEventListener("click",function(e){
                  this.classList.add("animating");
              },false);
              elts[i].addEventListener("animationend",function(e){
                  this.classList.remove("animating");
                  console.log("end");
              });
          }
          </script>

          如此,我們就可以為某些需要執行動畫的元素添加一個名為zr的class類即可;當然,此處是一個動畫效果,也可以是其他的某些操作;

          getElementsByClassName()方法與querySelector()和querySelectorAll()方法很類似,但用法及返回類型不同;

          var elts = document.getElementsByClassName("myclass outer");
          console.log(elts);  // HTMLCollection
          var elts = document.querySelectorAll(".myclass,.outer");
          console.log(elts);  // NodeList

          getElementsByClassName()參數只能是類名,且多個類名用空格隔開,多個類名是并的關系,而且不分順序,即只有所有class都匹配的元素才會被返回,其返回類型是HTMLCollection,是動態的集合;

          querySelector()參數是CSS選擇器,并且可以使用復雜的CSS選擇器,只要是合法的CSS選擇器都可以,但多個選擇器必須使用逗號分隔,它們是或的關系,其返回類型是NodeList,并且這個NodeList是靜態的;

          目前,獲取元素集合共有四個方法,要注意它們的不同點;

          var elts = document.getElementsByClassName("myclass outer");
          console.log(elts);  // HTMLCollection
          var elts = document.getElementsByTagName("div");
          console.log(elts);  // HTMLCollection
          var elts = document.getElementsByName("myname");
          console.log(elts);  // NodeList
          var elts = document.querySelectorAll(".myclass,.outer,.current");
          console.log(elts);  // NodeList

          另外,需要注意的是,getElementsByClassName()方法返回的是動態HTMLCollection,所以使用這個方法與使用getElementsByTagName()以及其他返回動態集合的DOM方法都具有同樣的性能問題;

          元素滾動:

          Element.scrollIntoView(alignToTop | scrollIntoViewOptions)方法:

          DOM對滾動頁面沒有做出規定;各瀏覽器分別實現了相應的方法,用于以不同方式控制滾動,最終HTML5選擇了scrollIntoView()作為標準方法;

          該方法是作為Element類型的擴展存在的,因此可以在所有元素上使用,通過滾動瀏覽器窗口或某個容器元素,使調用該方法的元素出現在視口中;

          該方法接收一個布爾值參數alignToTop或Object型(scrollIntoViewOptions)參數,如果為true或者省略,那么窗口會盡可能滾動到自身頂部與元素頂部平齊,如果為false,調用元素會盡可能全部出現在視口中,不過頂部不一定對齊;

          var mybtn = document.getElementById("mybtn");
          mybtn.onclick = function(){
              var img = document.getElementById("myimg");
              img.scrollIntoView(false);
          }

          Object型參數scrollIntoViewOptions:一個包含下列屬性的對象:

          • behavior:可選,定義動畫過渡效果,"auto"或 "smooth" 之一,默認為 "auto";
          • block:可選,定義垂直方向的對齊,"start", "center", "end", "nearest"之一,默認為 "start";
          • inline:可選,定義水平方向的對齊,"start", "center", "end", "nearest"之一,默認為 "nearest";
          img.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"});

          但是IE與Edge對scrollIntoViewOptions這個參數并不友好,比如不支持behavior:”smooth”等;

          var btn = document.getElementById("btn");
          btn.onclick = function(){
              var img = document.querySelector("img");
              // 以下三行是等同的
              img.scrollIntoView();
              img.scrollIntoView(true);
              img.scrollIntoView({behavior:"auto",block:"start"});
              // 以下兩行是等同的,但IE與Edge似乎不識別end
              img.scrollIntoView(false);
              img.scrollIntoView({behavior:"auto",block:"end"});
          }

          另外,CSS3中有個平滑滾動的屬性scroll-behavior,如;

          <style>
                  html,body{scroll-behavior: smooth;}
          </style>

          只要頁面有滾動行為,自動進行平常處理;但IE與Edge不支持;

          當頁面發生變化時,一般會用這個方法來吸引用戶的注意力;實際上,為某個元素設置焦點也會導致瀏覽器滾動并顯示出獲得焦點的元素;

          var username = document.getElementById("username");
          username.focus();

          Element.scrollIntoViewIfNeeded()方法:

          用來將不在瀏覽器窗口的可見區域內的元素滾動到瀏覽器窗口的可見區域,如果該元素已經在瀏覽器窗口的可見區域內,則不會發生滾動,此方法是標準的Element.scrollIntoView()方法的專有變體,不屬于任何規范,是一種WebKit專有的方法;

          var btn = document.getElementById("btn");
          btn.onclick = function(){
              var elt = document.getElementById("elt");
              elt.scrollIntoViewIfNeeded(true);
          }

          目前,除了Chrome和Opera支持,其他都不支持;

          應用的場景:

          對URL中hash標記的進化;比如:回到頂部(#);

          <a href="javascript:void(0)" id="topA" style="position:fixed;right:50px;bottom:50px;display:block; width:50px;height:50px;background-color:purple;">回到頂部</a>
          <script>
          // 回到頂部
          var topA = document.getElementById("topA");
          topA.onclick = function(){
              document.body.scrollIntoView({behavior:"smooth",block:"start"});
          }
          </script>

          滾動到指定位置(#xxx);

          如:一個單頁導航的應用;

          <style>
          *{margin:0; padding: 0;}
          html,body{
              -ms-overflow-style: none; scrollbar-width: none;
          }
          ::-webkit-scrollbar{ display: none; }
          ul,li{list-style-type: none;}
          header{
              position: fixed; top:0; left: 0;;
              width: 100%; height: 2rem; background-color: rgba(0, 0, 0, .5);
          }
          nav ul li{padding: 0 2rem; line-height: 2rem; float: left;}
          nav ul li a{color:#FFF; text-decoration: none;}
          section{width: 100%; height: 100vh; box-sizing: border-box; padding: 10%; background-size:cover;}
          section#banner{background: url(images/1.jpg) no-repeat center; background-size:cover;}
          section#service{background:url(images/2.jpg) no-repeat center; background-size:cover;}
          section#contact{background: url(images/3.jpg) no-repeat center; background-size:cover;}
          footer{
              width:100%;height: 2rem; background-color: rgba(0, 0, 0, .8); color:rgba(255, 255, 255, .8);
              position: fixed; left: 0; bottom: 0;
          }
          </style>
          <header>
              <nav>
                  <ul>
                      <li><a href="dom1.html">首頁</a></li>
                      <li><a href="#news" data-name="news">新聞</a></li>
                      <li><a href="#service" data-name="service">服務</a></li>
                      <li><a href="#about" data-name="about">關于</a></li>
                      <li><a href="#contact" data-name="contact">聯系</a></li>
                  </ul>
              </nav>
          </header>
          <section id="banner">
              <h2>零點程序員</h2>
              <h3>zeronetwork</h3>
          </section>
          <section id="news"><h2>新聞中心</h2></section>
          <section id="service"><h2>服務領域</h2></section>
          <section id="about"><h2>關于我們</h2></section>
          <section id="contact"><h2>聯系我們</h2></section>
          <footer><p>北京零點網絡科技有限公司,www.zeronetwork.cn 零點程序員</p></footer>
          <script>
          window.onload = function(){
              scrollPage();
              var navs = document.querySelectorAll("nav a");
              for(var i=0,len=navs.length; i<len; i++){
                  (function(){
                      var item = navs[i];
                      item.addEventListener("click",function(event){
                          event.preventDefault();
                          scrollPage(event.target.dataset.name);
                      },false);
                  })();
              }
          }
          function scrollPage(id){
              console.log(id);
              var section = id ? document.querySelector("#" + id) : document.body;
              section.scrollIntoView({behavior:"smooth",block:"start"});
          }
          </script>

          聊天窗口滾動顯示最新的消息;

          <style>
          *{margin: 0px; padding: 0;}
          html,body{font-size: 14px;}
          ul,li{list-style-type: none;}
          li{margin: 1.5vh 0;}
          #app{
              width: 400px; height: 400px; border: 10px solid purple;
              position: relative; background-color: rosybrown; 
              padding-bottom: 40px;
          }
          #message{ width: 100%; height:100%; padding:15px; padding-bottom: 0; 
              box-sizing: border-box; overflow-y: scroll;
          }
          #message ul{padding-bottom: 15px;}
          #message ul li{display: flex;}
          #message ul li.me{flex-direction: row-reverse;}
          #message ul li a{display: inline-block;}
          #message ul li a img{width: 2vw; height: 2vw; border-radius: 50%;}
          #message ul li p{
              background-color: #FFF; border-radius: 3px; padding:0.5vw; margin:0 3vw 0 1vw;
          }
          #message ul li.me p{background-color:#09ce44;margin: 0 1vw 0 3vw;}
          #inputdiv{
              position: absolute; left: 0; bottom: 0; width: 100%; height: 40px; 
              background-color:rgba(0, 0, 0, 1); padding: 5px; box-sizing: border-box;
              display:flex;
          }
          #txtInput{flex-grow: 3;}
          #btn{flex-grow: 1;}
          </style>
          <div id="app">
              <div id="message">
                  <ul>
                      <li><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
                      <li class="me"><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
                      <li class="me"><a href="#"><img src="images/1.jpg" /></a><p>..</p></li>
                      <li><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
                      <li class="me"><a href="#"><img src="images/1.jpg" /></a><p>...</p></li>
                  </ul>
              </div>
              <div id="inputdiv"><input type="text" id="txtInput" name="txtInput" />
              <input type="button" value="發送" id="btn" /></div>
          </div>
          <script>
          window.onload = function(){
              var ul = document.querySelector("#message>ul");
              if(navigator.userAgent.indexOf("Trident") != -1){
                  ul.scrollIntoView(false);
              }else{
                  ul.scrollIntoView({behavior:"smooth", block:"end"});
              }
              var btn = document.querySelector("#btn");
              btn.addEventListener("click",function(e){
                  var txtInput = document.querySelector("#txtInput");
                  if(txtInput.value){
                      var html = "<li class=\"me\"><a href=\"#\"><img src=\"images/1.jpg\" /></a>";
                      html += "<p>" + txtInput.value + "</p></li>";
                      document.querySelector("#message ul").insertAdjacentHTML("beforeend", html);
                      txtInput.value = "";
                  }
                  if(navigator.userAgent.indexOf("Trident") != -1){
                      ul.scrollIntoView(false);
                  }else{
                      ul.scrollIntoView({behavior:"smooth", block:"end"});
                  }
              },false);
          }
          </script>

          焦點管理:

          HTML5也添加了輔助管理DOM焦點的功能;

          document.activeElement屬性:

          該屬性始終會引用DOM中當前獲得了焦點的元素;

          元素獲得焦點的方式有頁面加載、用戶輸入和在代碼中調用focus()方法,如:

          console.log(document.activeElement);
          var btn = document.getElementById("myButton");
          btn.focus();
          console.log(document.activeElement === btn);  // true

          默認情況下,文檔剛剛加載完成時,document.activeElement中保存的是document.body元素的引用,文檔加載期間,其該屬性的值為null;

          一般情況下,都是在一個表單控件上應用焦點管理,比如,在一個input或textarea上選擇文本時,activeElement屬性就會返回該元素;

          在現實中,該屬性在控件中使用時,一般會與選擇控件中的文本操作配合使用,比如,調用該控件的selectionStart()和selectionEnd()方法來獲取選擇的文本內容;

          <input type="text" id="myinput" value="北京零點網絡科技有限公司" /><br/>
          <textarea id="mytextarea" rows="5" cols="40">北京零點網絡科技有限公司推出零點程序員品牌,專門從事IT培訓,主講是大師哥王唯。</textarea>
          <p>獲得焦點的元素:<b id="outputelement"></b></p>
          <p>選擇的文本:<b id="outputtext"></b></p>
          <script>
          function selectText(e){
              var activeEl = document.activeElement;
              var selection = activeEl.value.substring(
                  activeEl.selectionStart, activeEl.selectionEnd
              );
              var outputelement = document.getElementById("outputelement");
              var outputtext = document.getElementById("outputtext");
              outputelement.innerHTML = activeEl.id;
              outputtext.innerHTML = selection;
          }
          var myinput = document.getElementById("myinput");
          var mytextarea = document.getElementById("mytextarea");
          myinput.addEventListener("mouseup", selectText,false);
          mytextarea.addEventListener("mouseup", selectText,false);
          </script>

          小示例:

          // 獲取焦點的控件自動滾到頁面中間
          window.addEventListener("click",function(e){
              var elt = document.activeElement;
              if(elt.tagName == "INPUT" || elt.tagName == "TEXTAREA")
                  elt.scrollIntoView({behavior:"smooth", inline:"center"});
          },false);

          解決由于窗口縮放、鍵盤彈出后遮擋表單的問題:

          <!-- 按tab切換到input,再縮放窗口大小 -->
          <h1 tabindex="1">Web前端開發</h1>
          <div style="height: 1000px; background-color: purple;" id="mydiv" tabindex="2">div</div>
          <input type="text" />
          <script>
          window.addEventListener("resize",function(e){
              if(document.activeElement.tagName === 'INPUT' ||
                  document.activeElement.tagName === 'TEXTAREA'){
                  setTimeout(function(){
                      document.activeElement.scrollIntoView({behavior:"smooth"});
                  },100);
              }
          });
          </script>

          activeElement屬性是只讀的,如果想讓某個元素獲取焦點,可以調用該元素的focus()方法,如:

          var myinput = document.getElementById("myinput");
          document.activeElement = myinput;  // 失效
          myinput.focus();
          console.log(document.activeElement);  // input

          document.hasFocus()方法:

          該方法用于表明當前文檔或者當前文檔內的節點是否獲得取焦點,該方法可以用來判斷當前文檔中的活動元素是否獲得了焦點,如:

          console.log(document.hasFocus());

          當查看一個文檔時,當前文檔中獲得焦點的元素一定是當前文檔的活動元素,但一個文檔中的活動元素不一定獲得了焦點,例如,一個在后臺窗口中的活動元素一定沒有獲得焦點;

          通過檢測文檔是否獲得了焦點,可以知道用戶是不是正在與頁面交互;

          <input id="btn" type="button" value="打開窗口" /><br/>
          <script>
          function openWin(){
              window.open("about:blank","newwin","width=400,height=300");
          }
          var btn = document.getElementById("btn");
          btn.addEventListener("click", openWin, false);
          function checkPageFocus(){
              if(document.hasFocus())
                  console.log("該頁面獲得了焦點");
              else
                  console.log("該頁面失去了焦點");
          }
          setInterval(checkPageFocus, 1000);
          </script>

          查詢文檔獲知哪個元素獲得了焦點,以及確定文檔是否獲得了焦點,這兩個功能最重要的用途是提高Web應用的無障礙性;無障礙Web應用的一個主要標志就是恰當的焦點管理,而確切地知道哪個元素獲得了焦點是一個比較重要的操作;

          HTMLDocument的增強:

          HTML5擴展了HTMLDocument,增加了新的功能;

          document.readyState屬性:

          該屬性描述了document 的加載狀態,當該屬性值發生變化時,會在 document 對象上觸發 readystatechange事件;

          IE4最早為document對象引入了readyState屬性,然后,其他瀏覽器也都陸續實現了這個屬性,最終HTML5把這個屬性納入了標準之中。

          該屬性有三個可能的值:

          • loading:正在加載文檔;
          • interactive:可交互的,文檔已被解析,"正在加載"狀態結束,但是諸如圖像,樣式表和框架之類的資源仍在加載;
          • complete:文檔和所有資源已完成加載,表示load狀態的事件即將被觸發;
          console.log(document.readyState);  // loading

          為什么要使用document.readyState屬性?目的就是通過它來實現一個指示文檔已經加載完成的指示器;在這個屬性沒有得到廣泛支持前,要實現這樣的一個指示器,必須借助onload事件處理程序,表明文檔已經加載完畢;

          window.onload = function(){
              console.log("文檔加載完畢")
              console.log(document.readyState);  // complete
          }
          現在可以直接使用document.readyState屬性來判斷,如:
          // 不會被執行,因為代碼運行到此處,readySate狀態為loading
          if(document.readyState == "complete"){
              console.log("文檔已加載完畢");
              console.log(document.readyState);
          }

          但并沒有執行,因為代碼執行到此處,readyState的狀態為loading,而后它又不能自己更新,所以要實時的取得readyState的狀態;當該屬性值發生變化時,會在 document 對象上觸發 readystatechange事件,所以使用該事件就可以實時監聽它的狀態;

          document.onreadystatechange = function(e) {
              // if(document.readyState == "loading"){
              //     console.log("Loading");
              // }else if(document.readyState == "interactive"){
              //     var span = document.createElement("span");
              //     span.textContent = "資源正在加載";
              //     document.body.appendChild(span);
              //     console.log("Interactive");
              // }else if(document.readyState == "complete"){
              //     var span = document.querySelector("span");
              //     document.body.removeChild(span);
              //     console.log("Complete");
              // }
              // 或者
              switch(document.readyState){
                  case "loading":
                      console.log("Loading");
                      break;
                  case "interactive":
                      // 文檔已經結束了“正在加載”狀態,DOM元素可以被訪問。
                      // 但是像圖像,樣式表和框架等資源依然還在加載。
                      var span = document.createElement("span");
                      span.textContent = "資源正在加載";
                      document.body.appendChild(span);
                      console.log("Interactive");
                      break;
                  case "complete":
                      // 頁面所有內容都已被完全加載
                      var img = document.getElementsByTagName("img")[0];
                      console.log("圖片等資源加載完成:" + img.src);
                      break;
              }
          }

          一個簡單小示例,loading頁

          <style>
          *{margin: 0; padding: 0;}
          #loading{
              width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, .6);
              position: absolute; top: 0; left: 0;
          }
          @keyframes rotate{
              0%{transform: rotate(0deg);}
              100%{transform: rotate(360deg);}
          }
          #loading img{
              width: 5vw;
              position: absolute; left: 50%; top:50%;
              margin-left: -5vw; margin-top:-5vh;
              animation: rotate 1s linear infinite;  /* [??nf?n?t] */
          }
          #loading.loading-none{display: none;}
          </style>
          <div id="loading"><img src="images/loading.png" /></div>
          <script>
          document.onreadystatechange = function(e) {
              if(document.readyState == "complete")
                  document.getElementById("loading").className = "loading-none";
              else
                  document.getElementById("loading").className = ""
          }
          </script>

          compatMode兼容模式:

          頁面的渲染有兩種方式,Standards mode標準模式和Quirks mode混雜模式(也稱為怪異模式);

          這兩種模式主要影響CSS內容的呈現,某些情況下也會影響JavaScript的執行;所以,在開發時,確定瀏覽器處于何種模式很重要;

          起先,是從IE6開始區分渲染頁面的模式是Standards mode還是Quirks mode;IE為此給document對象添加一個名為compatMode屬性,該屬性即用于識別瀏覽器處于什么模式;如果是標準模式,返回CSS1Compat,反之返回BackCompat;后來,其他瀏覽器也實現了這個屬性,最終HTML5也把這個屬性納入標準;

          console.log(document.compatMode);  // CSS1Compat

          目前,存在以下幾種情況:

          瀏覽器都是根據是否有DOCTYPE聲明判斷,有則為標準模式,值為CSS1Compact,無則為混雜模式,值為BackCompact;因此,一條好習慣就是每個html文檔都要有doctype聲明;

          對于有DOCTYPE聲明,但瀏覽器不能正確識別,則使用混雜模式,值為BackCompact;

          如果有xml聲明 <?xml version="1.0" encoding="utf-8"?>也是混雜模式;

          另外,如果文檔的第一行是標簽或文本,也為混雜模式;

          對于IE來說,這兩種模式差別很大,但對其他瀏覽器來說,差別很小,因此,這兩種模式的判斷和差別主要是針對IE;

          兩種模式的具體差別:

          在Standards Mode下對于盒模型的解釋所有瀏覽器都是基本一致的,但在Quirks Mode模式下則有很大差別;

          在Standards mode中:

          元素真正的寬度 = margin + border-width + padding + width;

          在Quirks mode中:

          元素真正的寬度 = width,而其內容寬度 = width - (margin – padding - border-width);

          在標準模式下,所有尺寸都必須包含單位,否則會被忽略,而在混雜模式下,可以不帶單位,如:style.width = "20",相當于"20px";

          當一個div元素中包含的內容只有圖片時,在標準模式下的所有瀏覽器中,在圖片底部都有4像素的空白;但在混雜模式下,div距圖片底部默認沒有空白;

          兩種模式獲取視口的方式是不同的;

          console.log(document.body.clientHeight);
          console.log(document.documentElement.clientHeight);

          就是說,在BackCompact模式下,取得document的某些屬性,如clientWidth、scrollLeft等,使用的是document.body,而標準模式下,使用的是document.documentElement,如:

          var height = document.compatMode == "CSS1Compat" ? document.documentElement.clientHeight : document.body.clientHeight;
          console.log(height);

          documentMode文檔模式:

          IE8為document對象添加了documentMode屬性,即文檔模式(document mode),該屬性與compatMode屬性緊密相關,但該屬性不是標準屬性,除了IE,其它瀏覽器都不支持;

          console.log(document.documentMode);  // 11

          頁面的文檔模式決定了可以使用什么功能,如,文檔模式決定了可以使用哪個級別的CSS,可以在Javascript中使用哪些API,以及如何對待文檔類型;

          在IE8中,有三種不同的呈現模式:

          • 為5,則為混雜模式(IE5),IE8或更高版本中的新功能無法使用;
          • 為7,表示IE7仿真模式,IE8或更高版本中的新功能無法使用;
          • 為8,表示IE8標準模式,IE8中的新功能都可以使用,如可以使用Selectors API,更多CSS2級選擇器和某些CSS3功能,還有一些HTML5的功能;不過IE9中的新功能無法使用;

          從IE8往后,都遵循了這一規律,比如,為9,表示IE9標準模式,支持ES5,CSS3和更多HTML5的功能;

          有了這個屬性,就能準確的判斷IE的各種版本了,如:

          var isIE = !!(window.ActiveXObject || "ActiveXObject" in window);
          var ieMode = document.documentMode;
          var isIE7 = isIE && ieMode && ieMode == 7;
          var isIE8 = isIE && ieMode && ieMode == 8;
          var isIE9 = isIE && ieMode && ieMode == 9;
          var isIE10 = isIE && ieMode && ieMode == 10;
          console.log(isIE);  // true
          console.log(isIE10);  // 切換到10版本,返回true

          X-UA-Compatible:

          開發者還可以主動要求客戶端按照什么文檔模式進行渲染,也就是強制瀏覽器以某種模式渲染頁面,此時可以使用HTTP頭部信息X-UA-Compatible,或通過等價的<meta>標簽來設置:

          <meta http-equiv="X-UA-Compatible" content="IE=IEVersion">

          IEVersion有可能有以下值:

          • Edge:始終以最新的文檔模式來渲染頁面;忽略文檔類型聲明;
          • EmulateIE9(8、7):如果有文檔聲明,則以IE9(8、7)標準模式渲染頁面,否則將文檔模式設置為IE5;
          • 9、8、7、5:強制以IE9(8、7、IE5模式)標準模式渲染頁面,忽略文檔類型聲明;

          如:讓文檔模式像在IE7中一樣,可以:

          <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">

          如果不考慮文檔類型聲明,而直接使用IE8標準模式,可以:

          <meta http-equiv="X-UA-Compatible" content="IE=8">

          再如,強制以IE5混雜模式渲染:

          <meta http-equiv="X-UA-Compatible" content="IE=5" />

          如果在IE8以下的瀏覽器中設置,是無效的,因為該設置是在IE8才開始有的;

          使用最新的文檔模式:

          <meta http-equiv="X-UA-Compatible" content="IE=edge"/>

          IE瀏覽器將總是使用最新版本的文檔模式;

          另外,也可以同時設置多個值,中間用逗號隔開;

          <meta http-equiv="X-UA-Compatible" content="IE=IEVersion">

          注意,由右向左進行嘗試,即先使用IE8模式,如果失敗,則使用IE模式;

          最流行的設置:

          <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>

          chrome=1表示可以激活Chrome Frame;

          如果安裝了Google Chrome Frame(谷歌瀏覽器內嵌框架)則使用谷歌瀏覽器內核模式,甚至會使用Chrome的控制臺,否則使用最新的IE模式;

          head屬性:

          在HTML5規范中新增了document.head屬性,引用文檔的<head>元素,屬于HTMLHeadElement類型;

          console.log(document.head);
          console.log(document.head === document.querySelector("head"));

          各主流瀏覽器均支持,但為了兼容低版本的,也可以結合備用方式,如:

          var head = document.head || document.getElementsByTagName("head")[0];

          如果有多個<head>元素,則返回第一個;

          document.head 是個只讀屬性,為該屬性賦值只會靜默失敗,如果在嚴格模式中,則會拋出TypeError異常;

          字符集屬性:

          HTML5新增了幾個與文檔字符集有關的屬性,其中,charset屬性表示實際使用的字符集,也可以用來指定新字符集;可以通過<meta>元素、響應頭部或直接設置charset屬性修改這個值,但實際上是只讀的,現在已經被characterSet替代,該屬性是只讀屬性,返回當前文檔的字符編碼,該字符編碼是用于渲染此文檔的字符集,如:

          console.log(document.charset);  // UTF-8

          此時,可以修改文檔的字符集設置,如:

          // IE與老版的Edge返回gb2312,其它默認失敗
          document.charset = "gbk";
          console.log(document.charset);  // UTF-8
          console.log(document.characterSet);
          // 同上,但所有瀏覽器靜默失敗
          document.characterSet = "gbk";
          console.log(document.characterSet);

          另一個屬性是defaultCharset,表示根據默認瀏覽器及操作系統的設置,當前文檔默認的字符集應該是什么,該屬性不是標準屬性,沒什么用處;

          console.log(document.defaultCharset);  // 只有IE與Safari有值

          data-自定義數據屬性:

          HTML5定義了一種標準的、附加額外數據的方法,即在HTML5文檔中,任意以”data-”為前綴的小寫的屬性名稱都是合法的,這樣的屬性被稱為數據集屬性,目的是為元素提供與渲染無關的信息,或者提供語義信息;這些屬性可以任意添加、隨便命名,只要以data-開頭即可,如:

          <div id="mydiv" data-appId="1234" data-myname="wangwei"></div>

          HTMLElement.dataset屬性:

          在Javascript中也為Element對象上定義了dataset屬性,該屬性指代一個對象,是元素的data-特性的實時、雙向的接口;

          dataset屬性的值是DOMStringMap接口的一個實例,被用于容納和展示元素的自定義屬(特)性,它就是一個名值對的映射,在這個映射中,每個data-name形式的屬性都會有一個對應的屬(特)性,只不過屬性名沒有data-前綴,比如,dataset.x保存的就是data-x屬(特)性的值;帶連字符的屬(特)性對應于駝峰命名屬性名,如:data-web-test屬(特)性就變成dataset.webTest屬性;如:

          <div id="mydiv" data-appId="001" data-subtitle="zeronetwork" data-web-description="零點程序員"> 
          // Javascript
          var mydiv = document.getElementById("mydiv");
          console.log(mydiv.dataset);  // DOMStringMap
          console.log(mydiv.dataset.subtitle);  // zeronetwork
          console.log(mydiv.dataset.webDescription);  // 零點程序員
          console.log(mydiv.dataset.appid);  // 只能小寫,不能是appId 

          設置或刪除dataset的一個屬性就等同于設置或移除對應元素的data-屬(特)性,并且在將鍵值轉換為一個屬性的名稱時會使用相反的轉換;

          // 判斷有沒有該屬性
          if(mydiv.dataset.myname){
              console.log(mydiv.dataset.myname);
          }
          mydiv.dataset.subtitle = "wangwei";  // 修改
          mydiv.dataset.imgurl = "images/1.jpg";  // 添加
          mydiv.dataset.userName = "wangwei";  // 添加,被轉換為data-user-name
          delete mydiv.dataset.subtitle;  // 刪除
          遍歷DOMStringMap對象;
          for(var k in mydiv.dataset){
              console.log(k + ":" + mydiv.dataset[k]);
          }

          與getAttribute()和setAttribute()相比:

          在效率上,dataset沒有上述兩個方法高,但是,這個影響可以忽略不計;從操作上來看,雖然使用dataset不能提高代碼的性能,但是對于簡潔代碼,提高代碼的可讀性和可維護性是很有幫助的,如:

          <div class="user" data-id="123" data-user-name="wangwei" data-sex="男" data-date-of-birth="1998/8/8"></div>
          <div class="user" data-id="124" data-user-name="jingjing" data-sex="女" data-date-of-birth></div>
          <div class="user" data-id="125" data-user-name="juanjuan" data-sex="女" data-date-of-birth="1995/5/5"></div>
          <script>
          var users = document.querySelectorAll(".user");
          // 使用getAttribute()和setAttribute()
          for(var i=0,len=users.length; i<len; i++){
              var user = users[i];
              var id = user.getAttribute("data-id");
              var username = user.getAttribute("data-user-name");
              var sex = user.getAttribute("data-sex");
              if(!user.getAttribute("data-date-of-birth"))
                  // user.setAttribute("data-date-of-birth","2020-1-1");
              var dateofbirth = user.getAttribute("data-date-of-birth");
              console.log("ID:" + id + ",username:" + username + ",sex:" + sex + ",dateofbirth:" + dateofbirth);
          }
          // 使用dataset
          for(var i=0,len=users.length; i<len; i++){
              var user = users[i];
              var id = user.dataset.id;
              var username = user.dataset.userName;
              var sex = user.dataset.sex;
              if(!user.dataset.dateOfBirth)
                  user.dataset.dateOfBirth = "2020/1/1";
              var dateofbirth = user.dataset.dateOfBirth;
              console.log("ID:" + id + ",username:" + username + ",sex:" + sex + ",dateofbirth:" + dateofbirth);
          }
          </script>

          另外,dataset屬性在IE中,只有IE11支持,所以在低版本的IE中,如果要使用dataset屬性,必須做兼容性處理;

          if(mydiv.dataset){
              console.log(mydiv.dataset.subtitle);
              console.log(mydiv.dataset.webDescription);
          }else{
              console.log(mydiv.getAttribute("data-subtitle"));
              console.log(mydiv.getAttribute("data-web-description"));
          }
          // 封裝一個函數
          function getDataset(elt){
              if(elt.dataset)
                  return elt.dataset;
              var attrs = elt.attributes,  // 元素的屬性集合
                  dataset = {},   // 包裝的一個屬性集對象
                  name,   // 要獲取的特性名
                  matchStr;  // 匹配結果
              for(var i=0, len = attrs.length; i<len; i++){
                  // 匹配data-自定義屬性
                  matchStr = attrs[i].name.match(/^data-(.+)/);
                  if(matchStr){
                      // 轉成小駝峰
                      name = matchStr[1].replace(/-([\da-z])/gi, function(all, letter){
                          return letter.toUpperCase();
                      });
                      dataset[name] = attrs[i].value;
                  }
              }
              return dataset;
          }
          var dataset = getDataset(mydiv);
          console.log(dataset);

          另外data-屬性并不是只在Javascript中使用,在CSS中應用的場景也很多,如:

          <style>
          p[data-font-size='2em']{font-size: 2em;}
          p[data-font-size='3em']{font-size: 3em;}
          </style>
          <p data-font-size="3em">零點程序員</p>
          <p data-font-size="2em">王唯</p>
          // 又如
          <style>
          #mydiv::after{background-color: rgba(0,0,0,.2); content: attr(data-content);}
          </style>
          <div id="mydiv" data-content="王唯是好人">大師哥</div>

          dataset應用的場景還是非常多的,一般來說,為了給元素添加一些不可見的數據,并要進行后續的處理,就可以用到自定義數據屬性;比如,配合CSS開發一些動畫效果,或在跟蹤鏈接等應用中,通過自定義數據屬性能方便地知道點擊來自頁面中的哪個部分;

          <a href="https://www.zeronetwork.cn" data-title="零點網絡">零點網絡</a>
          <script>
          window.onload = function(){
              var aElts = document.querySelectorAll("a");
              for(var i=0,len=aElts.length; i<len; i++){
                  aElts[i].addEventListener("click",function(e){
                      e.preventDefault();
                      doDataset(this);
                  },false);
              }
              var aDataset = [];
              function doDataset(elt){
                var o = {title:elt.dataset.title, href:elt.href, page:location.pathname};
                  aDataset.push(o);
                  console.log(aDataset);
              }
          }
          </script>
          // 小示例
          <style>
          .banner{
              background:url("images/2.jpg") no-repeat center; background-size:cover;
          }
          .fadeInDown{opacity: 0; transform: translateY(20px);}
          </style>
          <div class="banner"> 
              <h2 class="fadeInDown" data-duration=".8" data-delay="400">零點程序員</h2>
              <h3 class="fadeInDown" data-duration="1" data-delay="800">大師哥王唯</h3>
              <p class="fadeInDown" data-duration="1" data-delay="1000"><a href="#">更多</a></p>
          </div>
          <script>
          window.onload = function(){
              var elts = document.getElementsByClassName("fadeInDown");
              // for(var i=0,len=elts.length; i<len; i++){
              //  (function(){
              //      var elt = elts[i];
              //      var dataset = elt.dataset;
              //      setTimeout(function(){
              //          elt.style.opacity = 1;
              //          elt.style.transform = "translateY(-20px)";
              //          elt.style.transition = "all " + dataset.duration + "s linear";
              //      }, dataset.delay);
              //  })();
              // }
              Array.prototype.forEach.call(elts, function(v,k){
                  console.log(v);
                  var dataset = v.dataset;
                  setTimeout(function(){
                      v.style.opacity = 1;
                      v.style.transform = "translateY(-10px)";
                      v.style.transition = "all " + dataset.duration + "s linear";
                  }, dataset.delay);
              });
          }
          </script>

          Web前端開發之Javascript

          4月份最后一周了。今日前端早讀課文章由@騰訊P&P Design授權分享。

          @騰訊P&Pdesign全稱Platform & Publish Design,隸屬于騰訊互動娛樂發行線下的設計中心,團隊由視覺、交互、多媒體、UI開發人才構成,負責為騰訊游戲平臺體系和發行業務提供體驗和服務設計,包括WeGame平臺、QQ游戲平臺、游戲本地化設計、端游手游助手、移動社區等業務;致力于游戲平臺、UI、社區設計領域的研究和沉淀

          正文從這開始~~

          導語

          在夜深人靜的時刻,我們終于可以更加肆無忌憚地打開wegame進行快樂的游戲。那是因為WeGame終于上線暗色模式功能啦,能讓用戶更加舒適的閱讀體驗。

          為了追求更好的用戶體驗,WeGame在今年2月上線了暗色模式的功能,暗色模式給用戶提供了一種更輕松的方式來接觸游戲世界。給用戶帶來更加不同的可視性,給產品帶來了全新的體驗,讓用戶有更個性化的選擇。

          瀏覽器暗色模式動畫

          客戶端暗色模式動畫

          是不是迫不及待想體驗一下暗色模式了?點擊WeGame右上角設置,彈出設置彈框,即可選擇深色模式體驗。

          起源

          為什么想推進Wegame暗色模式?

          1、滿足不同Wegame游戲用戶風格偏好:

          Wegame自2018年TGP升級到WEGAME品牌 ,風格由深色風格調整為淺色風格,據調研淺色更利于用戶信息閱讀。但不少用戶更偏好深色風格,因為深色烘托游戲氛圍。且夜晚游戲期間夜間暗色閱讀體驗會更好。

          夜間暗色閱讀體驗會更好

          2、暗色模式是種體驗設計流行趨勢

          很多品牌都推出了各自版本的暗色模式,我們熟知的Windows、mac、Google等在自己的設計體系里早已有暗色模式設計;暗色模式在產品體驗設計中的流行趨勢的關注度由此開始上升,暗色模式設計逐漸被行業更多地重視起來到并發展成一種趨勢。

          資料來源于網絡

          3、提升用戶體驗

          暗色模式的屏幕能讓手機起到明顯的省電效果,同時夜晚更能保護用戶眼睛更舒服的瀏覽。

          資料來源于網絡

          前期技術方案探索

          早在一年前我們就開始對平臺性站點如何高效低成本實現多主題方案進行探索預研。

          問題痛點

          俗話說:文明的多樣性體現在軟件領域,是一個絕對的災難。

          做研發的同學都能感受到在迭代頻繁的大型平臺項目,要想換新主題一是件非常難的事

          1、平臺性站點開發主題成本高

          換主題對視覺,開發規范統一性要求非常高,可能你會說這不就是簡單的換膚嗎?是的是換膚邏輯,對于幾個頁面的小站點不算什么難事。但對于平臺項目就有難度,如:WeGame項目十分復雜,共有10+個子項目 ,包括平臺、商城、直播、300+個游戲助手等,國內版、國際版,端內版本,端外版本(適應各游戲平臺風格),另外個性化要求高導致模塊復用低,這讓整體的換膚就會變得不可能完成的任務,其成本巨大。

          2、迭代更新維護成本高

          每次迭代都需要去顧忌其它皮膚的表現,每次迭代更新,你有多少套皮膚就需要去更改多少套皮膚的樣式,這對開發成本太大。

          如何低成本,高效率的設計,開發與維護個性化主題?

          解決思路:提煉規律,讓機器代替人工,我們研究探索了一套設計體系驗證了其可行性。

          解決方案

          打造一套設計系統–P&P UIKIT

          P&P 設計系統是讓團隊理解并使用一種統一的設計語言進行設計與開發落地的方法,它貫穿于從設計到開發執行過程中,致力于維系體驗統一以及提升設計到開發效率。

          設計系統組成

          我們從組件化角度出發,建立標準底層組件庫,增強各業務模塊的底層復用;抽離底層視覺語言并傳遞到每個頁面每個模塊。確保風格一致性。再通過設計工具,開發框架的升級確保組件在業務團隊中執行。規則統一才能找出規律,才能找到讓機器代替人工工業化生產。邏輯如下所示:

          這里將重點分享換膚機制:

          Token\組件庫在設計中的應用

          換膚重要就是換視覺語言,因此Token前期提煉到后期到每個元素的應用規則的整理是最重要的環節。

          1、Token(視覺語言/設計變量)

          Token可以叫視覺語言或叫設計變量是設計標準規范的核心部分,是傳遞品牌統一重要因素,也是設計和開發實現統一的橋梁

          做設計的同學都知道,畫面中任何一個元素都是由點線面組成同樣在Web實現也是如此,UI界面元素可以抽象其通用屬性,不同的屬性參數組成不同的元件,如背景,邊線,文字,尺寸,陰影,圓角。

          因此 我們將這些屬性與具體的樣式解偶,將這些通屬能定義為Token,他們是背景,邊線,文字,尺寸,陰影,圓角。

          2、讓Token與組件關聯

          充分發揮XD軟件作用,利用XD工具設計師將設計Token通過層層關聯到組件中,它們會在傳達品牌的個性時起到十分重要的作用,讓整體保持視覺的一致性。

          同理,前端開發也需要按同一規范將Token值代碼化關聯到每個開發組件中

          效果:通過Token讓設計師在設計過程中快速換膚

          僅通過Token替換迅速將規范生成深色版,并直接應用到業務中去

          3、設計與開發如何協同

          在迭代過程中難以避免設計師需要優化Token顏色的情況,如果讓上下游對接和溝通更高效呢?

          我們開發了XD的Token插件能一鍵將 Token(XD文件)轉化成技術Sass變量代碼

          4、主題管理編譯工具:用替換Token生成相應主題樣式

          當一個站點為用戶提供多套主題功能時,在迭代過程中同時維護幾套主題成本就更高了,當原模塊樣式要做優化修改時,同時還需要兼顧多套主題樣式是否適配問題?,F正流行的暗黑模式與淺色模式就存在這樣的維護成本。

          通過Token及管理工具自動生成(N )份主題皮膚

          一份平臺樣式表通過不同的Token生成對應的樣式文件,迭代時同時編譯主題,只需關注當前版本,無需顧慮其它版本是否存在樣式問題。也無需手動復制相應樣式文檔,送到到指定的項目目錄。

          針對僅平臺體驗統一的需求,僅需要通過一級Token編譯生成

          好處:自動化管理樣式,后期維護簡單,安全性高,僅維護一套樣式代碼

          WEBGAME深色模式落地過程總結

          WeGame的深色模式落地的過程中我們遇到了多個挑戰,WeGame承載著非常多的項目。量大體小是它獨有的特點,成千上萬的頁面,數以萬計的圖片要如何處理,技術上如何實現等等是我們在改造項目中遇到的難點。

          我們整理為以下幾個問題及要點進行介紹:

          • 基于P&P UIKit 探索深淺換膚方案介紹;
          • 如何將大批量的SCSS變量轉換為CSS變量?
          • 頁面圖標及圖片如何支持深淺色換色?
          • 定制化項目換色方案

          基于P&P UIKit 探索深淺換膚方案介紹

          我們項目中使用 P&P UIKit 主要解決了多主題的設計及開發(如WeGame國內版及國際版)但在深淺換膚的需求中,假如按照多主題的方式進行資源的動態引入樣式,頁面在切換過程中會存在資源的網絡加載,并且多主題樣式之間存在樣式重復冗余,我們需考慮深淺樣式切換帶來的平滑感,因此需要思考一下如何優雅的實現深淺換膚。

          a. 使用Prefers-color-scheme 實現頁面需根隨系統深淺主題切換:

          WeGame 客戶端外頁面需根隨系統主題切換而進行深淺切換,我們在端外可采用CSS @prefers-color-scheme ,在返回值為dark mode 時,將文件中的 CSS 變量值切換深色主題色值實現切換,在不支持prefers-color-scheme的低版本瀏覽器中,將保持淺色模式的設計。

          b. 客戶端內場景實現深淺切換;

          WeGame 客戶端內瀏覽器內核為 QBlink70 版本,不支持CSS prefers-color-scheme,因此,我們采用桌面客戶端與前端頁面進行通信的方式,在開發過程中將CSS變量聲明放在約定好的CSS Class中,當桌面客戶端返回接口數據給頁面前端時,頁面前端進行切換 CSS Class 實現切換深淺主題。

          c. 保證切換體驗平滑度

          在開發過程中我們只維護一份源碼,將深淺兩份Tokens同時引入入口CSS文件,資源一次性請求,避免了在深淺模式切換過程中的加載感,實現了平滑切換深淺模式。

          2、如何將大批量的SCSS變量轉換為CSS變量?

          我們的深淺模式切換,項目源碼中存在大量的SCSS文件,文件中存在非常多的SCSS變量,SCSS變量編譯為CSS后,會被編譯為具體值,因此,我們需要考慮如何高效的將大量的SCSS轉換為CSS變量的寫法來實現切換深淺主題。

          解決方案:

          我們針對這個場景問題,將SCSS轉換為CSS變量的功能加入到PDP-theme中進行“無感知”編譯,項目文件基于 PDP-theme 可以迅速將大量SCSS文件中的SCSS變量編譯為CSS變量進行使用,同時編譯過程中我們還加入了兼容IE的處理,這個功能使我們不需要額外維護CSS變量,開發方式不受影響。

          IE瀏覽器兼容性處理問題方案:

          兼容低版本瀏覽器不支持CSS變量的寫法

          E瀏覽器不支持多CSS媒體屬性:使用@media prefers-color-scheme來根據系統顏色進行切換主題色的方法不能奏效。因為IE用戶不多,所以我們并沒有針對IE場景去做深淺換膚,我們首要考慮的是頁面能否在IE瀏覽器正常顯示。

          3、頁面圖標及圖片如何支持深淺色換色?

          (1) 小圖標換色支持方案

          我們采用將位圖圖標切換成svg圖標的方法。將位圖圖標切換成svg圖標,不僅可以支持換色,同時還可以利用svg Sprite Loader插件打包,防止相同的svg在頁面上重復繪制path,影響性能。

          symbol元素展示

          我們在定義了一組圖形對象(使用 <symbol>元素)之后,就可以使用 <use>元素來對它進行無限次實例化展示。你使用xlink:href屬性來指定你想要展示哪一組圖標。

          (2) 大圖背景換色支持方案

          WeGame平臺內有459款,每個游戲都有自己的助手頁。

          每個助手頁都有獨立特色的背景大圖,針對深淺背景圖案,在過去設計師通常會設計兩版不同的背景大圖:

          商城淺色背景

          商城深色背景

          深淺背景色

          那么多的游戲助手頁,要分別設計兩款不一樣的背景大圖,顯然是不可能的,我們的解決方案是:給背景加上一個深色的蒙層遮住

          未加背景蒙層

          加背景蒙層后

          4、定制化項目換色方案

          WeGame平臺承載著很多的項目,其中不乏存在一些有獨立特色風格的項目,以三大助手為例:LOL助手、CF助手、DNF助手。

          三大助手的主題色與wegame主題色不同,舉個例子:wegame的主題顏色是黃色,三大助手各自主題色文字在wegame的通用背景色下,對比對不明顯且不易識別。

          所以我們遇到的最大問題是配色問題:

          我們的思路是先沿用wegame的配色體系去修改三大助手,再由設計師走查重構稿調整優化。

          1.設計師再提取項目的二級主題色token

          LOL助手二級主題色token

          CF助手二級主題色token

          二級token要如何使用,這么你不得不夸贊一下pdp-theme的優勢,我們的開發同學早早在pdp-theme里擴展了這項功能,自研的工具可以實時的針對問題點及時更新優化。

          2.設計師再結合當前項目風格調整wegame一級token色值

          從預研到落地,我們面對諸多的挑戰,最終在今年的2月初,能支持深色模式的WeGame終于與大家見面了。說到這里還不快去體驗一下?

          這里是云端源想IT,幫你輕松學IT”

          嗨~ 今天的你過得還好嗎?

          憂慮像一把搖椅

          它可以使你有事做

          但不能使你前進一步

          - 2024.04.10 -


          在深入探討CSS變形動畫之前,讓我們先探討一下掌握它之后你可以實現哪些有趣的效果。


          學習了CSS變形動畫之后,你將能夠為你的網頁添加引人注目的動態效果,例如創建一個立體的3D魔方,或者設計一個引人入勝的旋轉菜單。這些僅僅是眾多可能性中的一小部分,但或許可以勾起我們的學習興趣。

          一、什么是CSS變形動畫?

          CSS變形動畫是利用CSS3的transform屬性創建的動畫效果。它可以使元素旋轉、縮放、傾斜甚至翻轉,讓靜態的網頁元素動起來,為用戶帶來更加豐富的交互體驗。


          坐標系統

          首先我們要學習的變形動畫,想達到在上圖中出現的3D效果單純的X與Y兩個軸是實現不了的,還需要加入一條縱深軸,即Y軸的參與才有一個3D的視覺感受。


          那么如何來理解X,Y,Z這三條軸的關系呢?可以看一下下面這張圖。

          • X軸代表水平軸
          • Y軸代表垂直軸
          • Z軸代表縱深軸


          X和Y軸都非常好理解,怎么理解這個Z軸呢?


          CSS的中文名稱叫做層疊樣式表,那么它肯定是一層一層的。之前學習過z-index就是用來設置層的優先級,優先級越高越在上面,也可以理解為離我們肉眼越近,它把優先級低的層給蓋住了,所以Z軸可以理解為我們觀察的視角與被觀察物體之間的一條軸。


          • Z軸數值越大,說明觀測距離越遠。
          • Z軸的數值可以無限大,所以設置的時候一定要小心。


          二、變形操作

          使用 transform 來控制元素變形操作,包括控制移動、旋轉、傾斜、3D轉換等。

          下面我們通過一些例子來演示一下,比較常用的變形操作:


          2.1 位移 translate()

          translate()函數可以將元素向指定的方向移動,類似于position中的relative?;蛞院唵蔚睦斫鉃?,使用translate()函數,可以把元素從原來的位置移動,而不影響在X、Y軸上的任何Web組件。


          想象一下,當你滾動頁面時,一個元素平滑地從一個位置滑向另一個位置,這種流暢的過渡效果可以大大提升用戶體驗。



          translate我們分為三種情況:

          1)translate(x,y)水平方向和垂直方向同時移動(也就是X軸和Y軸同時移動)

          2)translateX(x)僅水平方向移動(X軸移動)

          3)translateY(Y)僅垂直方向移動(Y軸移動)


          實例演示:通過translate()函數將元素向Y軸下方移動50px,X軸右方移動100px。


          HTML代碼:

          <div class="wrapper">
          <div>我向右向下移動</div>
          </div>


          CSS代碼:

          .wrapper {
          width: 200px;
          height: 200px;
          border: 2px dotted red;
          margin: 20px auto;
          }
          .wrapper div {
          width: 200px;
          height: 200px;
          line-height: 200px;
          text-align: center;
          background: orange;
          color: #fff;
          -webkit-transform: translate(50px,100px);
          -moz-transform:translate(50px,100px);
          transform: translate(50px,100px);
          }


          演示結果:


          2.2 旋轉 rotate()

          旋轉rotate()函數通過指定的角度參數使元素相對原點進行旋轉。旋轉不僅可以是固定的度數,還可以是動態變化的,創造出無限的可能性。


          它主要在二維空間內進行操作,設置一個角度值,用來指定旋轉的幅度。如果這個值為正值,元素相對原點中心順時針旋轉;如果這個值為負值,元素相對原點中心逆時針旋轉。如下圖所示:


          HTML代碼:

          <div class="wrapper">
          <div></div>
          </div>


          CSS代碼:

          .wrapper {
          width: 200px;
          height: 200px;
          border: 1px dotted red;
          margin: 100px auto;
          }
          .wrapper div {
          width: 200px;
          height: 200px;
          background: orange;
          -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
          }


          演示結果:


          2.3 扭曲 skew()

          扭曲skew()函數能夠讓元素傾斜顯示。這種效果常常用于模擬速度感或者傾斜的視覺效果。


          它可以將一個對象以其中心位置圍繞著X軸和Y軸按照一定的角度傾斜。這與rotate()函數的旋轉不同,rotate()函數只是旋轉,而不會改變元素的形狀。skew()函數不會旋轉,而只會改變元素的形狀。



          Skew()具有三種情況:

          1)skew(x,y)使元素在水平和垂直方向同時扭曲(X軸和Y軸同時按一定的角度值進行扭曲變形);

          第一個參數對應X軸,第二個參數對應Y軸。如果第二個參數未提供,則值為0,也就是Y軸方向上無斜切。


          2)skewX(x)僅使元素在水平方向扭曲變形(X軸扭曲變形);


          3)skewY(y)僅使元素在垂直方向扭曲變形(Y軸扭曲變形)


          示例演示:

          通過skew()函數將長方形變成平行四邊形。

          HTML代碼:

          <div class="wrapper">
          <div>我變成平形四邊形</div>
          </div>


          CSS代碼:

          .wrapper {
          width: 300px;
          height: 100px;
          border: 2px dotted red;
          margin: 30px auto;
          }
          .wrapper div {
          width: 300px;
          height: 100px;
          line-height: 100px;
          text-align: center;
          color: #fff;
          background: orange;
          -webkit-transform: skew(45deg);
          -moz-transform:skew(45deg)
          transform:skew(45deg);
          }


          演示結果:


          2.4 縮放 scale()

          縮放 scale()函數 讓元素根據中心原點對對象進行縮放。這不僅可以用來模擬放大鏡效果,還可以創造出元素的進入和退出動畫,比如一個圖片慢慢縮小直至消失。



          縮放 scale 具有三種情況:

          1) scale(X,Y)使元素水平方向和垂直方向同時縮放(也就是X軸和Y軸同時縮放)。

          例如:

          div:hover {
          -webkit-transform: scale(1.5,0.5);
          -moz-transform:scale(1.5,0.5)
          transform: scale(1.5,0.5);
          }

          注意:Y是一個可選參數,如果沒有設置Y值,則表示X,Y兩個方向的縮放倍數是一樣的。


          2)scaleX(x)元素僅水平方向縮放(X軸縮放)


          3)scaleY(y)元素僅垂直方向縮放(Y軸縮放)


          HTML代碼:

          <div class="wrapper">
          <div>我將放大1.5倍</div>
          </div>


          CSS代碼:

          .wrapper {
          width: 200px;
          height: 200px;
          border:2px dashed red;
          margin: 100px auto;
          }
          .wrapper div {
          width: 200px;
          height: 200px;
          line-height: 200px;
          background: orange;
          text-align: center;
          color: #fff;
          }
          .wrapper div:hover {
          opacity: .5;
          -webkit-transform: scale(1.5);
          -moz-transform:scale(1.5)
          transform: scale(1.5);
          }


          演示結果:

          注意:scale()的取值默認的值為1,當值設置為0.01到0.99之間的任何值,作用使一個元素縮?。欢魏未笥诨虻扔?.01的值,作用是讓元素放大。


          2.5 矩陣 matrix()

          matrix() 是一個含六個值的(a,b,c,d,e,f)變換矩陣,用來指定一個2D變換,相當于直接應用一個[a b c d e f]變換矩陣。就是基于水平方向(X軸)和垂直方向(Y軸)重新定位元素。



          此屬性值使用涉及到數學中的矩陣,我在這里只是簡單的說一下CSS3中的transform有這么一個屬性值,如果需要深入了解,需要對數學矩陣有一定的知識。


          示例演示:通過matrix()函數來模擬transform中translate()位移的效果。
          HTML代碼:

          <div class="wrapper">
          <div></div>
          </div>


          CSS代碼:

          .wrapper {
          width: 300px;
          height: 200px;
          border: 2px dotted red;
          margin: 40px auto;
          }
          .wrapper div {
          width:300px;
          height: 200px;
          background: orange;
          -webkit-transform: matrix(1,0,0,1,50,50);
          -moz-transform:matrix(1,0,0,1,50,50);
          transform: matrix(1,0,0,1,50,50);
          }

          演示結果:

          想要快速入門前端開發嗎?推薦一個前端開發基礎課程,這個老師講的特別好,零基礎學習無壓力,知識點結合代碼,邊學邊練,可以免費試看試學,還有各種輔助工具和資料,非常適合新手!點這里前往學習哦!「鏈接」

          2.6 原點 transform-origin

          任何一個元素都有一個中心點,默認情況之下,其中心點是居于元素X軸和Y軸的50%處。如下圖所示:


          在沒有重置transform-origin改變元素原點位置的情況下,CSS變形進行的旋轉、位移、縮放,扭曲等操作都是以元素自己中心位置進行變形。


          但很多時候,我們可以通過transform-origin來對元素進行原點位置改變,使元素原點不在元素的中心位置,以達到需要的原點位置。



          transform-origin取值和元素設置背景中的background-position取值類似,如下表所示:


          示例演示:

          通過transform-origin改變元素原點到左上角,然后進行順時旋轉45度。

          HTML代碼:

          <div>
          <div>原點在默認位置處</div>
          </div>
          <div class="wrapper transform-origin">
          <div>原點重置到左上角</div>
          </div>

          CSS代碼:

          .wrapper {
          width: 300px;
          height: 300px;
          float: left;
          margin: 100px;
          border: 2px dotted red;
          line-height: 300px;
          text-align: center;
          }
          .wrapper div {
          background: orange;
          -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
          }
          .transform-origin div {
          -webkit-transform-origin: left top;
          transform-origin: left top;
          }


          演示結果:

          以上就是css動畫中幾種基本的變形技巧了,掌握這些我們可以操控我們的網頁元素實現我們想要的一些基本動畫效果。


          在這個充滿創造力的時代,CSS變形動畫是每個前端開發者必備的技能。它不僅能提升用戶體驗,更能激發設計師和開發者的創意火花。所以,不妨嘗試一下,讓你的網頁動起來,給用戶留下深刻的印象吧!



          我們下期再見!


          END

          文案編輯|云端學長

          文案配圖|云端學長

          內容由:云端源想分享


          主站蜘蛛池模板: 国产电影一区二区| 久久人妻av一区二区软件| 亚洲AV无码一区二区三区在线观看 | 日韩精品一区二区午夜成人版| 一区二区在线电影| 亚洲色精品aⅴ一区区三区| 亚洲爽爽一区二区三区| 日本精品视频一区二区| 无码日韩人妻av一区免费| 亚洲丶国产丶欧美一区二区三区| 亚洲国产国产综合一区首页| 国产一区二区免费| 一区二区三区人妻无码| 久久99国产精品一区二区| 亚洲国产精品一区第二页 | 日韩人妻无码一区二区三区久久99| 精品国产AV无码一区二区三区| 亚洲香蕉久久一区二区| 亚洲欧美国产国产一区二区三区| 99精品一区二区三区| 麻豆一区二区三区精品视频| 国产一区二区成人| 在线成人综合色一区| 女人和拘做受全程看视频日本综合a一区二区视频 | 无码人妻一区二区三区免费手机| 一区二区视频在线观看| 国产一区二区三区不卡AV| 亚洲av日韩综合一区二区三区| 久久精品一区二区三区日韩| 少妇精品久久久一区二区三区| 久久er99热精品一区二区 | 精品无码一区二区三区爱欲九九| 久久久精品人妻一区亚美研究所| 亚洲天堂一区二区| 亚洲综合无码一区二区痴汉| 国产伦精品一区二区三区免.费 | 亚洲视频免费一区| 国产精品亚洲一区二区三区在线观看| 鲁大师成人一区二区三区| 国模无码人体一区二区| 激情亚洲一区国产精品|