1. 程式人生 > >css3學習以及移動端開發基本概念的思考

css3學習以及移動端開發基本概念的思考

    html{
      height:1000px;
      background-color: red;
     }
     @media screen and (width:2560px){
       html{
         background-color: blue;
       }
     }
注意:首先必須弄清楚,我們的width/height值得是瀏覽器的可視區域的大小(縮小或者放大瀏覽器會發生變化),而device-width和瀏覽器的縮放是沒有關係的。如我的iMac是

2560*1440,那麼當我縮小的時候顏色是紅色,而全屏的時候顏色就是藍色了!然而,如果我查詢device-width:2560px,那麼不管我如果縮小放大瀏覽器都是一樣的藍色!

<meta name="viewport" content="width=400">
此時在所有的手機上都是document.document.clientWidth,也就是[layout viewport!!!]都是400px; 在渲染頁面之前,瀏覽器需要知道layout viewport有多大,基於此瀏覽器可以計算比如20%的具體畫素寬度是多少。如果沒有指定,那麼瀏覽器就會自己設定一個layout viewport。8個瀏覽器中有6個會設定為980px,在黑莓中或者ie10中,值為1024px。
 html{
      height:1000px;
      background-color: red;
     }
     @media screen and (width:2580px){
       html{
         background-color: blue;
       }
     }
我們的responsive模組模擬的畫素就是真實的css畫素,與具體的dpr無關但是這時候我們在console中確實可以列印真實的dpr的,也就是我們模擬的這個裝置的dpr。如果我們模擬的裝置沒有設定dpr,那麼就是2,因為我的裝置的dpr就是2!如上面例子,我們把iMac的responsive中的width設定為2580會發現我們的背景色變成了藍色了!
<meta name="viewport" content="width=device-width, initial-scale=1">
做媒體查詢的時候一定要有上面這句程式碼:
    document.documentElement.clientWidth
   document.documentElement.clientHeight//獲取layout viewport
   window.innerWidth/window.innerHeight//獲取ideal viewport
 screen.width/screen.height反應的是整個電腦的屬性,我的筆記本是2560*1600,而且dpr是2,因此列印1280*800(這是在destop的情況下的,不要開啟模擬其他機型的情況下,請保持手機按鈕是灰色的,否則就是模擬器了,會查詢到模擬器的screen!!!!!)。哪怕你在responsive裡面模擬不同的dpr,但是因為這時候是css畫素同時是desktop,因此不會影響我的機器的screen.width/screen.height的。因為screen.width/screen.height只是和我們的顯示器有關,無法模擬但是如果你設定為我們所說的mobile,這時候我們模擬的就是還是css畫素,也就是說device-width查詢的是css畫素
  screen.width//在保持chrome手機按鈕是灰色的情況下,返回的一直是顯示器的寬度(不是裝置畫素而是CSS畫素)
  screen.width//如果手機按鈕不是灰色,那麼返回的是模擬的裝置的screen.width,而且也是CSS畫素
要記得這裡的media一般用all,screen,print 
 @media screen and (width:2580px){//screen/all/print,在responsive介面有一個標誌,表示的橫豎屏的轉換
       html{
         background-color: blue;
       }
     }
 媒體查詢和其在桌面環境上的工作方式一樣。width/height使用layout viewport做為參照物,並且以CSS畫素進行度量,device-width/device-height也是使用CSS畫素進行度量。換句話說,width/height是document.documentElement.clientWidth/Height值的映象,同時device-width/height是screen.width/height值的映象。(它們在所有瀏覽器中實際上就是這麼做的,即使這個映象的值不正確。)
 document.documentElement.clientWidth/clientHeight===width/height===layout viewport
  window.innerWidth/innerHeight===ideal viewport//理想視口CSS寬度和高度,包含滾動條。這時候的initial-scale必須是1!
  device-width/device-height==screen.width/screen.height//顯示器的CSS寬度和CSS高度
 window.pageXOffset和window.pageYOffset,包含了文件水平和垂直方向的滾動距離。所以你可以知道使用者已經滾動了多少距離。可以在chrome中開啟用iphone6+開啟csdn除錯
window.pageXOffset
window.pageYOffset

我們首先要弄清楚三個viewport:

ideal viewport(initial-sclae==1):這是我們最關心的viewport,他表示我們的視口到底有多少空間可以用於佈局(如iphone6+一直是414,也就是指代的具體的裝置寬度。特別注意:即使把initial-scale設定為0.5,那麼因為visual viewport width = ideal viewport width / zoom factor,所以ideal viewport也是不會變化的。這裡的zoom指代的就是initial-scale,minum-scale,max-scale等。也就是說三個viewport中,ideal viewport是固定不變的,是通過ideal viewport來計算visual viewport和layout viewport)

visual viewport:他會受到使用者縮放的影響,如果使用者放大了那麼其視口會變小。(如iphone6+的initial-scale設定為0.5,那麼visiual viewport=414/0.5=818)

layout viewport:如果使用者沒有指定就是980px,如果指定了device-width就是裝置寬度,如果指定了width=320px那麼就是320px(如iphone6+在initial-scale=0.5的情況下就是818)

注意:我們只要記住visual viewport width = ideal viewport width / zoom factor,也就是說我們是通過ideal viewport來計算visual viewport,layout viewport的。如果我們需要解決1px問題,這時候的就需要考慮到zoom了,inital-scale如果小於1那麼就能看到一個物理畫素寬度的線條了!

如下面的例子:

<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8" />
<title>linear-gradient()_CSS參考手冊_web前端開發參考手冊系列</title>
<meta name="viewport" content="initial-scale=0.5">
<style>
*{
	margin:0;
	padding:0;
}
div{
	background: -moz-repeating-linear-gradient(top left -45deg, #ace, #ace 5px, #f96 5px, #f96 10px);
	background: -webkit-repeating-linear-gradient(top left -45deg, #ace, #ace 5px, #f96 5px, #f96 10px);
	width: ;
	height:818px;
}

</style>
</head>
<body>
<div class="test"></div>

</body>
</html>
			
這時候我們看到如下的效果:


注意:通過修改initial-scale的值,我們的layout viewport,ideal viewport都變化了!

viewport的功能是用來約束你網站中最頂級包含塊元素(containing block)<html>的。那麼<html>元素的寬度是多少?它的寬度和瀏覽器視窗寬度一樣。這就是為什麼你的那個擁有width: 10%屬性的側邊欄會佔據整個瀏覽器視窗的10%。所有web開發者都很直觀的知道並且在使用它。你可能不知道的是這個行為在理論上是如何工作的。理論上,<html>元素的寬度是被viewport的寬度所限制的。<html>元素使用viewport寬度的100%。viewport,接著,實際上等於瀏覽器視窗:它就是那麼定義的。viewport不是一個HTML結構,所以你不能用CSS來改變它。它在桌面環境下只是擁有瀏覽器視窗的寬度和高度

//html元素的寬度受到viewport的限制和約束,但是viewport不是一個html結構無法使用CSS來約束它
所以clientWidth/Height在所有情況下都提供viewport的尺寸。但是我們去哪裡獲取<html>元素本身的尺寸呢?它們儲存在document.documentElement.offsetWidth和-Height之中。
 
 document.documentElement.clientWidth//viewport尺寸
   document.documentElement.offsetWidth//html尺寸

沒有方法直接計算scale,也就是zoom的值。我們要計算visual viewport的寬度,因為他和zoom的值成反比,zoom越大那麼visual viewport越小。而且zoom是相對於ideal viewport來說的
    [ideal viewport]= document.documentElement.clientWidth/Height//前提是設定了meta
     [html元素的寬度]= document.documentElement.offsetWidth/Height//獲取html元素的寬度
     [layout viewport]=meta標籤中設定的width
      visual viewport width = ideal viewport width / zoom factor
   zoom factor = ideal viewport width / visual viewport width
[Minimum and maximum zoom factors]=ideal viewport width / layout viewport width。這是因為根據公式zoom factor = ideal viewport width / visual viewport width,visual viewport width<=layout viewport width
initial-scale的作用
  首先把頁面初始的zoom值設定為一個指定的值,整個值是通過ideal viewport來計算的(通俗的講就是通過intial-scale來獲取visual viewport,然後把visual viewport設定為layout viewport)。因此會產生一個visual viewport width。然後把這個visual viewport width設定為layout viewport width的值

  <p>
    Setting he initial-scale directive actually does two things:
It sets the initial zoom factor of the page to the defined value, calculated relative to the ideal viewport. Thus it generates a visual viewport width.
It sets the layout viewport width to the visual viewport width it just calculated.
So let’s say we have an iPhone in portrait mode and give it an initial-scale=2 without any further instructions. By now, it shouldn’t surprise you that this sets the visual viewport width to 160px (= 320 / 2). That’s how the scaling directives work.
However, it also sets the width of the layout viewport to 160px. So we now have an 160px wide page in minimum zoom. (The visual viewport cannot become larger than the layout viewport, so zooming out is not possible.)
And no, this doesn’t make the slightest bit of sense. If asked for my candid opinion I’d probably mumble something like “completely fucking batshit insane.” Still, there’s no doubt that browsers behave like this.
 </p>

好幾個例子:

這裡查詢的是css畫素,而我的hello裝置是1920*1080的(dpr是3沒有影響),因此背景變成紅色了
@media screen and (max-width: 1920px) {
    body {
        background-color:red;
    }
}
因為我的mac的device-width是1280,因此這裡也是會列印紅色的
@media screen and (device-width: 1280px) {
    body {
        background-color:red;
    }
}
 GalaxyS5我們的css寬度為360*640,而dpr為3,因此螢幕的畫素為1080*1920,而我們的screen.width還是指代的是css畫素,因此為360。因此我們可以得出結論:screen.width/screen.height都是指代的css畫素,而不是螢幕真實的硬體畫素。因此width/device-width的媒體查詢都是查詢css畫素,這一點要弄清楚。如果是在電腦上,responsive就是返回mac的螢幕,否則就是模擬的手機的螢幕資訊
@media screen and (device-width: 360px) {
    body {
        background-color:red;
    }
}
這是我們的裝置的寬度和高度的比值,iphone6+是9/16的
@media screen and (device-aspect-ratio: 9/16) {
    body {
        background-color:red;
    }
}

很顯然兩個viewport都是以CSS畫素度量的。但是當進行縮放(如果你放大,螢幕上的CSS畫素會變少)的時候,visual viewport的尺寸會發生變化,layout viewport的尺寸仍然跟之前的一樣(至少我覺得是不一樣的,可以通過把nitial-scale進行縮放,然後列印document.documentElement.clientWidth)

visual viewport寬度 = ideal viewport寬度  / 當前縮放值

當前縮放值 = ideal viewport寬度  / visual viewport寬度

所以當initial-scale=1的時候,我們的ideal viewport==visual viewport、只有當用使用者zoom的時候兩者才是不一樣的或者由於initial-scale不是設定為1那麼因為存在縮放,那麼ideal viewport一直是414,而visisual viewport存在變化

(1)我們首先設定了initial-scale=1,這時候ideal viewport=visual viewport、如果我們的當前縮放值不是1,那麼如果要計算visual viewport可以按照上面的公式來計算。這是關於縮放值的,也就是zoom,這時候我們自己指定了initial-scale。如果我們自己不指定initial-scale(也就是不存在initial-scale/或者device-width來把可視區域寬度設定為ideal viewport),那麼會存在一個預設的initial-scale,這個預設的scale是按照當前縮放值 = ideal viewport寬度  / visual viewport寬度來計算的,但是我們無法得到Visual viewport的大小,但是我們知道Visual viewport<=layout viewport,所以我們至少縮小了的值就是=ideal viewport/layout viewport。至於為什麼Visual viewport是980,是因為View viewport代表的是可視區域的大小,在iPhone下會滿足不會出現滾動條,因此visual viewport就是我們的layout viewport(很顯然這時候不是顯示指定的initial-scale也就是不是相對於ideal viewport來說的了)。

(1.1)rem如何解決1px的問題

首先看一個現象,我們把initial-scale設定為1得到的document.documentElement.getBoundingClientRect().width為414px(在6plus下),如果我們把inital-scale設為0.5得到的就是818,那麼這個值代表什麼意義呢?

   var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;
        flexible.rem = win.rem = rem;
這一句程式碼呼叫,我們把寬度分為10份,如果在scale=1的時候,1rem=41.4px,在scale=0.5的情況下得到1rem=81.8px,但是很顯然scale=0.5的大小是scale=1元素大小的一半(使用px來衡量)。對比下面的圖:


這個是scale=0.5的圖


這裡是scale=1的圖,我們看看程式碼:

<div style='width:100px;height:100px;background-color: #ccc;'></div>
很明顯,這裡使用的px為單位的元素大小,如果你使用rem為單位,那麼你會發現initial-scale=0.5還是1沒有任何區別!為啥呢?
<pre name="code" class="javascript"> function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    }
在scale=1的時候我們的width=414px,而在scale=0.5的時候我們的width=818px,但是螢幕的大小是沒有發生變化的,所以該元素在initial-scale=1/2的情況下佔據的寬度為:100/414和100/818,因此顯然兩者佔據的寬度是不一樣的!但是如果是rem為單位,那麼情況就完全不一樣了。
 <div style='width:4rem;height:4rem;background-color: #ccc;'>111</div>
這時候我們的如果scale=1那麼1rem=41.4px,但是如果是scale=0.5那麼我們1rem=81.8px,因此元素佔據的螢幕寬度始終是相等的:4*41.4/414=4*81.8/818!但是為什麼要這麼做呢?答案是:解決1px問題,因為在retina螢幕下1px的css畫素會被解析為2的物理畫素,這是我們無法容忍的,但是如果我們把scale=0.5那麼就能夠解決這個問題。

 因為1rem=81.8px,也就相當於原來的1rem=41.4px,現在進行了更加細緻的劃分了,1px已經真正代表一個物理畫素了。那麼以後如果我需要設定一個200*200px的div那麼我只要這麼做:

第一步:設計師給我們750px畫素的設計稿,而且這個設計稿既是物理畫素也是邏輯CSS畫素。同時viewport都不需要自己設定了,因為js已經自己運行了!!!

第二步:剛才那個js已經執行後,所以data-dpr=2,同時initial-scale,max-scale等都會設定為0.5,那麼這時候我們的initial-scale設定為了0.5那麼按照上面的分析1rem=750px

第三步:剛才那個js執行後,計算docEl.getBoundingClientRect().width得到375,所以其css寬度只有375px畫素(因為他會取樣,這樣設定為750px設計稿保證在retina螢幕上顯示正常)

第四步:元素的寬度為200/75rem*200/75rem。

總結:我們如果使用了這種方式,那麼不能再使用px為單位了,因為scale後無法保證元素的大小是相同的,但是rem能夠保證!同時這種方式也會使的1px問題得到解決。詳見使用Flexible實現手淘H5頁面的終端適配 #17。我們計算了iPhone6下的佈局尺寸rem(750的設計稿對應於750的硬體畫素),而且1rem=75px(硬體畫素),因為我們計算出來的都是rem值,因此在其他裝置上會通過js重新計算1rem所對應的硬體畫素,從而做到1rem在不同的裝置上通過cm計算的尺寸是相同的,只不過是重新計算了一次inital-scale和document.documentElement的值而已!

(2)前端設計給我兩套圖片,一套是@1X還有一套是@2X,@1X200*200,@2X400*400,但是一定要注意:設計說的是CSS畫素,但是因為他們只是考慮dpr1的情況下的,所以也是物理畫素,因此對於下面的div元素就有:

 div{
   height:200px;
   width:200px;
}

如果在retina螢幕上,此時載入的是@2X的圖片,也就是400*400的,但是因為dpr2,所以css畫素還是200*200的;然而對於非retina螢幕上,我們的載入的200*200的圖片,但是因為dpr1,因此也是200*200css畫素。那麼為什麼200*200retina圖上會模糊呢?原因其實很簡單,因為載入的圖片是200*200,也就是物理畫素是200*200的,但是顯示的div卻顯示的物理畫素是400*400,因此原來的200*200的畫素相當於被拉伸了,因此也就模糊了。一般我們的css遵循下面的規則:

div{
    background-image:url(@1X);
}
@media screen(){
  background-image:url(@2X);
}

那麼很顯然後面的圖片是前面的圖片的4倍大小,但是如何做到頁面不迴流的。理由很簡單,因為後面載入的400*400的圖片是物理畫素,而dpr2,因此還是200*200css畫素,因此其原來的div佔據的大小是足夠的,因此壓根就不會迴流!!!【所以實現既可以通過rem實現也可以通過px實現】

(3)box-shadow相關(box-shadow優先順序低於background和border)

(3.1)inset下面,如果我們改變V距離,這時候如果是正數那麼是從上往下的,否則就是從元素的下邊往上邊的(出現哦)。水平距離也是一樣的道理
  (3.2)模糊距離就是在水平或者垂直移動的距離上面再次進行二次模糊!不可以為負數,模糊方式是基於高斯模糊的,也就是基於加權平均數的方式來完成的
(3.3)擴充套件為負數可以用來抵消或者疊加水平或者垂直的距離
  (3.4)注意我們的最終的層疊順序,邊框的層疊順序是比較高的,會覆蓋掉我們的box-shadow陰影,但是box-shadow是小於backgroung的
(3.5)我們的除錯結果是:如果blur的距離越大,那麼圓心都會被blur掉

(3.6)其實模糊不是基於圓心進行模糊的,而是在原來的投影的基礎上模糊的,而且是往內部模糊的,也就是越往內部越模糊,紅色越淡,所謂的blur表示的就是計算這個元素的顏色的時候使用周圍元素的顏色的半徑,因此當在外圍的時候我們會越來越模糊,因為越在外面本身的顏色已經很淡了,那麼模糊後更加淡!

box-shadow:inset 0 2rem 3rem -2rem white,
           inset 0 -4rem 4rem -2.5rem black;
 首先:第一個投影分析如下,2rem向下移動,-2rem的拓展表示又往上移動了2rem,所以最後的圓心還是在上邊框上
       這時候往下模糊3rem就是很顯然的效果了,而且這種模糊是從圓心往外模糊的,模糊半徑會在圓心兩側同時模糊,因此這裡才稱之為模糊半徑。
       第二個投影分析如下:-4rem表示往上移動4rem,然後拓展為-2.5rem,因為是負數表示收縮原來的移動,因此
       最後只是往上移動了1.5rem,這時候模糊了4rem,所以所有的位置都模糊了
       注意:inset時候是從圓心往外部模糊的,而且這裡完全不用第一個投影;不對,一定要記住上面的模糊是半徑,所以兩邊各一半才是正確的。而且對於水平方向的漸變來說第一個模糊壓根就是不需要的!!!
       之所以第一個模糊可以不需要是因為他是白色的,模糊後還是白色,因此當要保持一定寬度是純白才有用

投影一開始在沒有任何重疊的時候和原來的元素在同一個位置上,但是因為後面有了偏移而導致了移動:

div{
  width:250px;
height:70px;
box-shadow:-24px -24px 0 -20px red,24px 24px 0 -20px blue;
border:1px solid blue;
}

這個div雖然第一個投影在原來的位置上向左和向上移動了24px,但是因為後面用了陰影外延值導致其陰影實際的大小隻有4px

使用box-shadow作邊框有很多要注意的地方。注意使用時的層級關係(前篇有詳細講過),防止陰影出乎意料外的覆蓋(畢竟其不影響佈局),最後就是要考慮到陰影的大小始終是跟著box的高寬的,所以box寬高寬變化必須被考慮在內.

下面這個彩虹色邊框你應該明白boxs-shadow的層級關係,也就是前面的box-shadow的優先順序要比後面的優先順序高:

div{
box-shadow:20px 15px 0px #3c3,
 -20px 15px 0 #36c,
 20px -15px 0px #c63,
-20px -15px 0px #cc3;
width:100px;
height:100px;
margin:40px;
border:1px solid red;
}
現在回到下面的複雜的例子:
<style> 
.box{
  float: left;
  background: blue;
  width: 100px;
  height: 100px;
  margin-right: 10px;
  padding:0;
}
.box1{
  box-shadow: 0 0 0 20px red inset;
}
.box2{
  box-shadow: 10px 0 0 20px red inset;
}
.box3{
  box-shadow: 10px 0 10px 20px red inset;
}
.box4{
  box-shadow: 0 0 10px 40px red inset;
}
</style>
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
<div class="box box4"></div>
對於第一個box1來說,很顯然容易理解。box2來說,首先水平移動10px,所以投影在原來的位置上在左邊產生了10px的紅色區域,然後再來說擴充套件20px,因為拓展和水平移動可以疊加,所以現在左邊的紅色距離是20+10=30px,但是因為上邊和下邊只是拓展了20px,所以最後的結果就是上下為20px,對於右邊來說,因為左邊移動了10px,所有右邊有10px進入border下面了,所以必須要擴充套件10px後才會從右邊出來,最後的結果就是20-10=10px。因此左邊30px,上下20px,右邊10px的效果!


注意:上面都是通過擴充套件和移動的疊加來產生的絢麗效果,如果僅僅是沒有通過疊加而設定為0那麼這種效果是無法滿足的!之所以是這樣,是因為要考慮到其他邊的擴充套件情況,如果其他邊壓根沒有擴充套件那麼效果肯定不是我們想要的!下一個問題就是我們為什麼要設定負數的擴充套件呢:

原因:是為了去除上下或左右的模糊,因為進行模糊的時候預設會從投影邊開始,即使左右沒有發生移動那麼模糊的時候也會依據半徑進行模糊,那麼就不會形成我們需要的效果。

box-shadow:inset 0 2rem 3rem -2rem red;
效果如下:


這時候擴充套件了-2rem,那麼左右的邊界就會往裡面收2rem,所以當模糊的邊界是3rem,其實只有3/2=1.5rem那麼左右還是不會出來的,所以只有上下的漸變。如果我們設定為下面的形式:

box-shadow:inset 0 0 3rem 0 red;

很顯然,這時候左右都會擴充套件,而不是我們需要的僅僅上下擴充套件的情況,這就是為什麼需要把左右擴充套件設定為負數的原因!

(4)text-shadow相關

text-shadow: 1px 1px 0 #f96,-1px -1px 0 #f96;
這個程式碼可以實現描邊效果,因為第一個投影只是在元素的下邊和右邊有了紅色的投影,但是左邊和上邊還沒有投影的,所以就有了後面的第二個投影。因為同時投影的元素在往下移動的時候,雖然只是移動了幾個畫素,但是其他的畫素都會被覆蓋掉,因為投影的優先順序,也就是層疊順序是在是太低了,這一點一定要注意!
(5)rgba相關

  RGBA存在的問題就是繼承問題,解決的方法就是不讓其成為父子關係而是設定為兄弟關係,結合position:absolute定位,讓其一個作為背景而且z-index比較小,而另外一個作為真正的元素在背景上面z-index很大。對於IE來說就要使用fallback顏色,結合濾鏡來實現

(6)border-radius相關

border-radius還有一個大值特性,也就是值很大的時候,只會使用能夠渲染的圓角大小渲染(這也是為什麼可以用一個很大的border-radius和一個50%的值,注意:如果寬度和高度不一樣,這時候border-radius為50%就會按照寬度和高度的50%計算,得到的就是一個橢圓)。因此,要實現一個【正方形】元素的圓角效果(例如網站頭像),我們還可以使用一個很大的圓角值,同樣是不需要計算的;CSS3圓角除了大值特性,還有一個等比例特性,就是水平半徑和垂直半徑的比例是恆定不變的,也就是說如果你把border-radius設定為200px,那麼水平和垂直就是1:1,如果你設定200/300那麼就會按照2:3來設定!

.radius-test3 { width: 100px; height: 200px; border: 50px solid #cd0000; border-radius: 300px; }

上面的CSS水平方向是200px,垂直方向是300px,所以如果要轉換成為橢圓只要設定border-radius:100px/150px,但是如果僅僅設定300px,那麼表示水平垂直的border-radius要保持11,因此水平方向只能為100,垂直方向雖然可以是150,但是由於11的約束,最後只能也是100,最後就會形成跑道的效果!!!!

(7)transform,perspective相關

perspective屬性用來設定視點,在css3的模型中,視點是在Z軸所在方向上的

translateX,translateY表現出在螢幕中的上下左右移動,transformZ的直觀表現形式就是大小變化,實質是XY平面相對於視點的遠近變化(說遠近就一定會說到離什麼參照物遠或近,在這裡參照物就是perspective屬性)。比如設定了perspective200px;那麼transformZ的值越接近200,就是離的越近,看上去也就越大,超過200就看不到了,因為相當於跑到後腦勺去了,你不可能看到自己的後腦勺。(200-transformZ的值)就是視點和xy平面的距離(初始是螢幕的位置,此時transformZ的值為0)。

需要注意的一點是,整個座標系中各各座標軸的相對關係是固定的。正常情況下,視點和我們的眼睛是同一個方向的如同上面所講。而當執行如rotateX(90deg)等旋轉變換時,zy平面旋轉,z軸和y軸的指向也會變化90度。此時z軸指向上方(座標系方向會變化),[視點也是在上方],此時我們從螢幕上看的就不是直觀的元素大小變化,而是元素的升降變化,好像站在遠處在看【一部電梯】那樣(因為視角在Z軸上,所以是上下移動的了)

perspective屬性用在容器上時,容器內每個元素的表現形式會不一樣。當perspective屬性用再容器內每個元素身上時,會根據各自的設定值進行表現。打個比方就是你一個人平視盒子裡的10個雞蛋和十個你每人看1個一模一樣雞蛋。(地址:http://m.blog.csdn.net/article/details?id=39003061

下面這個例子可以用於說明z軸旋轉過後元素translateZ變化的具體表現

<div><img src="images/a9.png"></div><!--正常放置,無變化-->
<div style="perspective:300px"><img src="images/a9.png" style="transform:translateZ(40px)"></div><!--z軸朝著螢幕,圖片推向你所在的方向-->
<div style="perspective:300px"><img src="images/a9.png" style="transform:rotateX(90deg)"></div><!--Z軸朝天,視點在Z軸方向上-->
<div style="perspective:300px"><img src="images/a9.png" style="transform:rotateX(90deg) translateZ(60px)"></div><!--Z軸朝天,視點在Z軸方向上,朝視點推進,圖片上升-->
<div style="perspective:300px"><img src="images/a9.png" style="transform:rotateX(90deg) translateZ(-60px)"></div><!--Z軸朝天,視點在Z軸方向上,朝視點遠離,圖片下降-->

perspective:

(1)元素越近,也就是perspective越小,那麼如rotate等的作用越明顯,反之越不明顯


這裡是perspective=70的,同時第二個A進行了rotateX=45的效果。


這裡是perspective=700,同時第二個A進行了rotateX=45的效果。很顯然,perspective越大那麼表示長鏡頭,元素不會變形,越小表示廣鏡頭,元素會變形

perspective屬性對於3D變形來說至關重要。該屬性會設定檢視者的位置,並將可視內容對映到一個視錐上,繼而投到一個2D視平面上。如果不指定透視,則Z軸空間中的所有點將平鋪到同一個2D視平面中,並且變換結果中將不存在景深概念。上面的描述可能讓人難以理解一些,其實對於perspective屬性,我們可以簡單的理解為視距,用來設定使用者和元素3D空間Z平面之間的距離。而其效應由他的值來決定,值越小,使用者與3D空間Z平面距離越近,視覺效果更令人印象深刻;反之,值越大,使用者與3D空間Z平面距離越遠,視覺效果就很小。
上圖的效果完全說明了一切。父節點沒有設定perspective的情況下,梅花King的3D旋轉效果不明顯,而在父節點設定perspective後,梅花King才像個3D旋轉

transform-style,這個屬性預設為 flat,也就是隻要是這個 div 內的子元素,一律都是以扁平 ( flat ) 的方式呈現,所屬的變換 transform 也一律都是用 flat 的方式變換,換句話說就是沒有 Z 軸的存在,為了讓內容元素都是立體元素,所以我們要將 transform-style 設為 3D。在沒有設定 box 的 translateZ 或 rotate,讓 Z 的深度有所變化,攝影機透過 perspective 看出去的位置都是相同的,也造成不論怎麼去看這個 box 都是一樣的大小。

大概瞭解之後,來把 box 旋轉一下角度,看得應該就會更清楚,當攝影機變成廣角,也就是 perspective 變短,整個旋轉後變形也會更加明顯,大家可以用開發者工具修改 camera 的 perspective 就會明白。

我們加入多一點的 box,並且讓這些 box 的位置改變或旋轉,看看效果如何,這裡比較需要注意的地方,是我們必須要額外在每個 box 加入 position:absolute 的屬性,因為 div 本身為 block 屬性,會互相擠壓,要設定位置為絕對位置,才會正確地放在 space 裡頭。

例如今天我先讓 box 在 X 軸上水平位移 100px 再繞著 Y 軸順時針轉 60 度,和先繞 Y 軸順時針轉 60 度,再在 X 軸上頭水平位移 100px 的結果會完全不同,因為當我先繞了 Y 軸轉動,整個 X 軸也會跟著轉動,這時候再做水平位移,位置就會像是在深度做變換。[轉載]玩轉 CSS 3D: 原理篇

chrome中發現一個問題,那就是perspective一定要在rotateY(或rotateX)的前面

<div class="camera">
    <div class="space">
        <div class="box"></div>
    </div>
</div>
這是perspective使用的經典模式,我們看看css程式碼:
.camera{
    width:200px;
    height:200px;
    perspective-origin:center center;
    /*視線距離元素的距離是500px,如果元素本身的translateZ到達500就會出現一葉障目的情況。但是如果translatez時負數而且特別大,這時候就會變成一個點,因為元素已經遠遠離開視線了*/
    perspective:500px;
}
.space{
    width:100%;
    height:100%;
    border:1px dashed #000;
    /*空間元素必須設定transform-style:preserve-3d*/
    transform-style:preserve-3d;
}
.box{
    width:100px;
    height:100px;
    background:#069;
    transform:translateX(50px) translateY(50px) translateZ(0px);
    /*translateZ如果是負數而且非常小,如-10000就會發現元素已經看不見了*/
}
或者你也可以仔細研讀[轉載]玩轉 CSS 3D: 原理

(8)rotate部分(只要沒有通過origin修改都會是元素的中心):

rotateZ:正數為順時針,負數為逆時針!

.cube .front  {
  transform: translateZ( 100px );
  /*這裡的translateZ的值時元素寬度的一半,也就是(196+4)/2=100px*/
  border:1px solid blue;
}
.cube .back {
  /*轉動-180deg,之所以是這樣是為了設定一個骰子的反向的2,也就是從鏡子中看到的2的樣式!!!*/
  transform: rotateX( -180deg ) translateZ( 100px );
}
.cube .right {
  transform: rotateY(   90deg ) translateZ( 100px );
}
/*rotateY時候,正數為逆時針移動,負數那麼就是順時針*/
.cube .left {
  transform: rotateY(  -90deg ) translateZ( 100px );
}
.cube .top {
  /*rotateX時候,正數為順時針,負數為逆時針*/
  transform: rotateX(   90deg ) translateZ( 100px );
}
.cube .bottom {
  transform: rotateX(  -90deg ) translateZ( 100px );
}  
註釋:rotateX正數為順時針,rotateY順時針為負數!
(9)skew部分(只要沒有通過origin修改都會是元素的中心,都是在同一個位置):

skewX:逆時針為正數,順時針為負數(垂直中心線和Y軸的夾角,90°的時候元素變得很長,元素左邊到達螢幕最前面,收縮消失,成為一條橫線

skewY:順時針為正數,逆時針為負數(水平中心線於X軸夾角,90°的時候底邊在最前面並收縮成為一條線,成為一條豎線)

記住:[rotate時候Y反常,而skew的時候X反常!rotateY vs skewX]

(10)scale部分:

 scaleZ就需要好好琢磨

至於旋轉木馬的效果原理分析:

雖然每一個圖片都是繞著Y軸旋轉了一定的角度,但是他們並沒有和Y軸中心產生距離。因為我們要讓圖片移動是為了沿著Z軸移動,而且圖片在旋轉的時候Z軸也是移動了的,而且Z軸一直在圖片的中心的垂直線上。因此移動的距離就是我們按照數學計算出來的距離!

(11)backface-visiblity

div
{
position:relative;
height:60px;
width:60px;
border:1px solid #000;
background-color:yellow;
transform:rotateY(180deg);
-webkit-transform:rotateY(180deg); /* Chrome and Safari */
-moz-transform:rotateY(180deg); /* Firefox */
}
#div1
{
-webkit-backface-visibility:visbile;
-moz-backface-visibility:hidden;
-ms-backface-visibility:hidden;
}
#div2
{
-webkit-backface-visibility:visible;
-moz-backface-visibility:visible;
-ms-backface-visibility:visible;
}

div背面是否可見。而且backface-visibilty作用於空間元素上的:

<div class="container">
    <div class="cube backface-visibility-visible">
        <div class="side front">1</div> 
        <div class="side back">2</div>
        <div class="side right">3</div>
        <div class="side left">4</div>
        <div class="side top">5</div>
        <div class="side bottom">6</div> 
    </div>
</div> 
也就是作用於cubic元素的backface-visibility!

先讓 box 在 X 軸上水平位移 100px 再繞著 Y 軸順時針轉 60 度,和先繞 Y 軸順時針轉 60 度,再在 X 軸上頭水平位移 100px 的結果會完全不同,因為當我先繞了 Y 軸轉動,整個 X 軸也會跟著轉動,這時候再做水平位移,位置就會像是在深度做變換

(12)mix-blend-mode和background-blend-mode

mix-blend-mode:該CSS屬性作用是讓元素內容和這個元素的背景以及下面的元素髮生“混合”。而且mix-blend-mode預設情況下是會混合所有比起層疊順序低的元素的,如果我們希望值混合某一兩個元素,而不是全部,該怎麼辦呢?
可以試試使用CSS3 isolation:isolate
background-blend-mode:這個要更好理解一點,背景的混合模式。可以是背景圖片之間的混合,也可以是背景圖片和背景色的混合。需要注意的是,只能是background屬性中的背景圖片和顏色混合,而且只能在一個background屬性中。
CSS3 backgrounds多背景IE9+瀏覽器就開始支援了。因此,你想混合多圖,就是要逗號,一個一個寫在background屬性中就可以了,例如本Demo的兩個妹子:

.box {
    background: url(mm1.jpg) no-repeat center, url(mm2.jpg) no-repeat center; 
}

(13)isolation:isolate阻止混合

.box {
    background-color: #0074D9;
}
/*給inner這個元素新增一個isolation:isolate就可以阻止img和後面的box的背景色進行合併。isolation:isolate之所以可以阻斷混合模式的進行,
本質上是因為isolation:isolate建立一個新的層疊上下文(stacking context)。沒錯,之所以起作用,就是單純地因為建立了新的層疊上下文。本身並沒有做什麼特殊的事情。
或者我可以這麼大膽的說:“isolation:isolate除了建立層疊上下文,其他沒有任何鳥用!”而且只要能夠建立層疊上下文的元素都是可以阻止mix-blend-mode的行為的。
1.z-index值不為auto的position:relative/position:absolute定位元素。
2.position:fixed,僅限Chrome瀏覽器,其他瀏覽器遵循上一條,需要z-index為數值。
3.z-index值不為auto的flex項(父元素display:flex|inline-flex).
4.元素的opacity值不是1.
5.元素的transform值不是none.
6.元素mix-blend-mode值不是normal.
7.元素的filter值不是none.
8.will-change指定的屬性值為上面任意一個。
9.元素的-webkit-overflow-scrolling設為touch.(perspective也會產生一個層疊上下文)
*/
.inner {
    width: 256px;
    height: 256px;
    background: url(http://image.zhangxinxu.com/image/study/s/s256/mm1.jpg) no-repeat;   
    border:1px solid red; 
    isolation:isolate;/*建立了層疊上下文*/
}
.mode {
    position: relative;
    right: -100px;
    mix-blend-mode: darken;	
    border:5px solid red;
}
DOM結構如下:
<div class="box">
    <div class="inner">
        <img src="http://image.zhangxinxu.com/image/study/s/s256/mm2.jpg" class="mode">
    </div>
</div>

(14)層疊上下文如何影響元素在Z軸的順序

 display:flex與層疊上下文

.box {}
.box > div { background-color: blue; z-index: 1; }   
 /* 此時該div是普通元素,z-index無效。 */
.box > div > img { 
  position: relative; z-index: -1; right: -150px;     
  /* 注意這裡是負值z-index */
}
我們看看DOM結構和分析
 <!--
  為什麼img元素會被box元素的背景色覆蓋?
  (1)必須弄清楚,我們的層疊順序對於這一類的父子孫關係的DOM結構(原生的層疊順序)也是存在的,而不僅僅針對那些通過position定位而覆蓋在一起的元素(非原生的層疊順序)
  (2)層疊順序告訴我們,負值z-index的層疊順序在Block元素下面,此處的第二層div元素是一個Block元素
   (3)如果給box一個background-color那麼我們還是通過層疊順序來分析,因為第二個div元素預設佔據了第一個div元素的寬度,而且不是層疊上下文元素因此後來居上原則box元素被覆蓋
  (4)普通元素的z-index失效,但是普通元素和display:flex/inline-flex結合起來那麼我們的z-index又是有效果的。也就是說flex/inline-flex元素要形成層疊上下文是有條件的:條件1是父級需要是display:flex或者display:inline-flex水平,條件2是子元素的z-index不是auto,必須是數值。這時候子元素就會形成堆疊上下文!所以,我們把box新增一個display:inline-flex那麼box >div就會形成堆疊上下文了!
 -->
 <div class="box">
    <div>
    	<img src="./flex.jpg">
    </div>
</div>
mix-blend-mode於層疊上下文
.mode {
  position: absolute; 
  mix-blend-mode: darken;
  /*絕對定位的元素使用了 mix-blend-mode: darken*/
}  
/*box元素會鑽到圖片下面去*/  
.box {
  background: blue;       
  isolation: isolate;  
  /*isolation:isolate這個宣告是mix-blend-mode應運而生的。預設情況下,mix-blend-mode會混合z軸所有層疊在下面的元素,要是我們不希望某個層疊的元素參與混合怎麼辦呢?
  就是使用isolation:isolate。本義是用來隔離mix-blend-mode元素的混合*/
}
.box > img { 
  position: relative;
   z-index: -1;
}
DOM結構部分
<img src="flex.jpg" class="mode">
<div class="box">
<!--
 (1)因為這裡是img,而且z-index:-1,所以會導致box的藍色的背景色會覆蓋img圖片,從而我們看不到圖片。但是因為mode元素使用了mix-blend-mode: darken,
所以會和後面的藍色背景進行混合掉!
 (2)如果我們給box新增一個isolation: isolate那麼box就會產生一個層疊上下文,所以就會使得其在Z軸上具有較大的優先順序,比絕對定位的元素優先順序更高[後來居上]。
    而且因為box這時候是堆疊上下文,所以其背景的顏色就會比z-index為負數的元素層級更低!
-->
    <img src="./width-ani.png">
</div>
大家知道為什麼定位元素會層疊在普通元素的上面嗎?

根本原因就在於,元素一旦成為定位元素,其z-index就會自動生效,此時其z-index就是預設的auto,也就是0級別,根據上面的層疊順序表,就會覆蓋inline或block或float元素。而不支援z-index的層疊上下文元素天然z-index:auto級別也就意味著,層疊上下文元素和定位元素是一個層疊順序的,於是當他們發生層疊的時候,遵循的是“後來居上”準則深入理解CSS中的層疊上下文和層疊順序不依賴於Z-index的層疊上下文是auto也就是0級別,而該級別會低於我們的z-index為正數的級別)。

1.位於最低水平的border/background指的是層疊上下文元素的邊框和背景色。每一個層疊順序規則適用於一個完整的層疊上下文元素
2.原圖沒有呈現inline-block的層疊順序,實際上,inline-block和inline水平元素是同等level級別。
3.z-index:0實際上和z-index:auto單純從層疊水平上看,是可以看成是一樣的。注意這裡的措辭——“單純從層疊水平上看”,實際上,兩者在層疊上下文領域有著根本性的差異。

相關推薦

css3學習以及移動開發基本概念思考

html{ height:1000px; background-color: red; } @media screen and (width:2560px){ html{ backgrou

關於移動開發時iOS上滑屏卡頓的問題,以及電話類數字的樣式失控問題

img 頁面 通話 tips rem span cti 解法 並不是 寫在前面的話:   tips:寫移動的時候,那些頭部需要固定顯示在顯示屏頂部的,通常在PC端我會用fixed來寫。但是,在移動端,這並不是一個好方法,因為彈出輸入小鍵盤的時候,會造成fixed 的元素偏移

移動開發經常遇見的問題以及解決方案

誤差 cli 輸入關鍵詞 水平居中 arch asi 服務器 color del 1.移動端左右滑動右側有留白 出現這種問題的話查看一下自己的css中有沒有用到position:relative或者position:absolute,我做頁面的時候經常遇到這個問題,百分之

05-移動開發教程-CSS3兼容處理

由於 edge flexbox 當前 css屬性 頁面 webp .html 風格 CSS3的標準並沒有全部定稿,目前CSS3的標準分成了不同的模塊,具體的標準由各個模塊推動標準和定稿,標準制定的過程中,瀏覽器也在不斷的發新的版本來兼容新的標準。瀏覽器有時會給一些在試驗階段

vue2.0移動開發的相關外掛以及經驗總結

最近在用vue2.0做微信公眾號相關的前端開發,經過這次開發實踐,現將專案中用到的相關比較實用的外掛及遇到的相關問題進行整理,希望和大家共同交流… cssrem:一個CSS值轉REM的VSCode外掛; lib-flexible:移動端彈性佈局適配解決方案; vue-

大前端全棧CSS3移動開發

作者宣告:本部落格中所寫的文章,都是博主自學過程的筆記,參考了很多的學習資料,學習資料和筆記會註明出處,所有的內容都以交流學習為主。有不正確的地方,歡迎批評指正 本節課學習視訊來源:https://www.bilibili.com/video/av26090013/?p=1    

協作移動開發-學習整理

需求①:向上滑動時,將tab固定到頂部 參考博文:https://blog.csdn.net/liu__520/article/details/53676834 Version 1.0 po點程式碼出來,並不是完整的安,效果來說不是很好,後期優化再加動畫吧: constructo

移動開發規範以及基礎總結(速記)

移動裝置的基礎知識: 1 ios裝置: px:物理,解析度相關,硬體裝置。解析度越大顯示的細節越豐富。 pt:邏輯,連線物理和軟體的中介。pt,point ppi:每英寸px的數量 ,視網膜屏是ppi超過300的螢幕,iphone4開始 1.1 蘋果裝置以及解析度 裝置

關於移動開發寬度高度,字型以及rem寬度使用的總結

遇到的問題:如何適配不同的手機螢幕。 簡單的說media query可以解決一部分。但是media query目前是照著iphone5/iphone/iphone6s 三個不同尺寸來進行。 如果手機尺寸不在這三個範圍之內,那麼元素的寬度可以按

微信開發常用技巧(2)-ios微信開發alert上面顯示地址問題,以及移動提示框推薦

ios微信開發alert上面顯示地址問題 做微信開發的朋友可能會遇到: 安卓微信的alert(),沒有問題,ios微信的alert(),會tm很尷尬的出現你的document.domain地址 解:過濾程式碼如下 window.alert = function(name)

Zepto和Jquery的區別,以及在做移動開發時,我們為什麼選擇使用zepto

【今晚實在不想寫別的,所以決定把近兩天的收穫整理整理,那我們就簡單的來談談Zepto.js和Jquery的區別,以及在做移動端開發時,我們為什麼選擇使用zepto.js】 一、先來看看我們熟悉的jQuery的定義: jQuery它是一個JavaScript函式庫,執行快

H5移動開發學習總結

對於移動端開發而言,為了做到頁面高清的效果,視覺稿的規範往往會遵循以下兩點: 1.首先,選取一款手機的螢幕寬高作為基準(現在一般選取iphone6的375×667)。之前專案中也用到過iphone5的320×568。 2.對於retina螢幕(如: dpr=

不求甚解的深度學習教程(1)-邏輯迴歸基本概念以及代價函式

未來是人工智慧的時代! 提到深度學習,邏輯迴歸是最經典的一個例子,也是很多教材的入門演算法(比如吳恩達的深度學習)。鑑於本人零基礎學習人工智慧的痛苦經歷,所以用通俗的語言把邏輯迴歸講清楚。深度學習本身核心知識是數學知識,涉及到線性代數、概率論,微積分等。體會到很多讀者都是像我一樣,已經把這些知識早就還給老師了

關於<meta>的各種用處以及移動的常見問題

字母自動大寫 mpat 自動 col code log spa capi flex 1.優先使用最新版本的IE和Chrome <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> 2

移動開發用touch事件還是click事件

device 問題 桌面網站 有意義 用戶 雨後春筍 phone 平臺 系統 前端開發現在包含了跨瀏覽器,跨平臺(不同操作系統)和跨設備(不同尺寸的設備)開發。 在移動開發的過程中,到底選取touch事件還是click事件?對了,請不要鄙視click,click在移動端開發

移動開發流程分享

規範 文檔 alt 計劃 技術分享 自動化測試 理想 流程 image 1.由於產品及UI能力限制,不能達到理想狀態,從以往項目開發中總結發現,在開發及測試周期中發現需求缺陷問題,需要花費大量的溝通成本,導致項目周期有所影響並嚴重影響開發效率和開發質量,解決方案:再產品需求

手機移動開發註意事項:

apple input元素 交互設計 代碼 文字 box webkit ack 包括 1、meta 標簽使用 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, u

探究移動開發

這樣的 ips AMF js設置 密度 hone 背景 設置 htm   什麽使移動端開發呢?這就是在手機等移動端設備上的網頁開發。 並且現在手機上的app有一部分也是h5頁面,對於Android系統的手機,我們打開手機上的開發者選項,開啟顯示布局邊界,如果發現頁面有布局則

移動開發註意事項

ror ng- wid 手動 ade scale conf storm 轉換 移動端開發中需要註意的事項,以及可能需要用到一些框架,尾部總結了一些主流框架,如果你覺得有用的話,請點擊推薦,謝謝! 一、關於meta 常見的公共meta屬性: 1、viewport <m

vue移動開發全家桶

高效 listener loading match ui組件 attribute lis click status 一句命令搞定全家桶: npm install vue-router vue-resource vuex --save main.js配置: impo