整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

第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生成相应主题样式

当一个站点为用户提供多套主题功能时,在迭代过程中同时维护几套主题成本就更高了,当原模块样式要做优化修改时,同时还需要兼顾多套主题样式是否适配问题。现正流行的暗黑模式与浅色模式就存在这样的维护成本。

通过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之间的任何值,作用使一个元素缩小;而任何大于或等于1.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

文案编辑|云端学长

文案配图|云端学长

内容由:云端源想分享