0做爲一個特殊的符號,常常會跟瀏覽器打交道,在不一樣的場景下,0表明的意思不盡相同,所以瀏覽器眼中的0不必定就是符合人們感官上的認識,那究竟瀏覽器會怎麼對待它呢,今天咱們就來探究一下各類場景中0的含義及瀏覽器的處理方式。css
setTimeout在js中經常使用來推遲任務的執行,能夠經過第二個參數設置延遲的毫秒數(若是不設置,默認爲0),在一些代碼中,能夠看到delay=0的狀況,以下:html
window.setTimeout(() => { ...... }, 0);
瞭解js的同窗應該知道,setTimeout的回調函數不會在定時器超時後當即執行,若是delay大於0,比較好理解,但delay是0的時候呢,瀏覽器會怎麼對待呢,這裏要分兩種狀況:
1.)timer嵌套
'Timers can be nested; after five such nested timers, however, the interval is forced to be at least four milliseconds.'
也就是setTimeout嵌套超過5層的,而且延遲不到4ms,纔會變成4ms,一樣適用於setInterval,所以在這種狀況下,delay=0其實會被設置成4;
2.)timer沒有嵌套
在沒有嵌套狀況下,對於chrome來講,delay=0也會設置成1;
說完瀏覽器的處理方式以後,咱們來看看網上搬過來的一個例子吧:node
setTimeout(()=>{console.log(5)},5) setTimeout(()=>{console.log(4)},4) setTimeout(()=>{console.log(3)},3) setTimeout(()=>{console.log(2)},2) setTimeout(()=>{console.log(1)},1) setTimeout(()=>{console.log(0)},0)
chrome打印結果:1 0 2 3 4 5;
firefox打印結果:0 1 2 3 4 5;
edge打印結果:1 2 0 3 4 5;
qq瀏覽器打印結果:1 0 2 3 4 5;
360瀏覽器打印結果:1 0 2 3 4 5;
從上面的打印結果來看,firefox是符合代碼預期的,edge打印與chrome稍有不一樣,應該是edge處理delay=0狀況稍有不一樣(設置成了2),qq和360瀏覽器跟chrome保持一致。
0ms定時器
在MDN文檔上,還說到一種實現0ms延時的定時器的實現方案,大致思路是自定義一個setZeroTimeout
方法,經過 postMessage
來觸發定時回調的執行,具體可看 https://dbaron.org/log/20100309-faster-timeouts ;
node的setTimeout
說完瀏覽器中的setTimeout,咱們再來看看nodejs中的是否同樣呢,能夠經過nodejs的源代碼窺探一二:git
// https://github.com/nodejs/node/blob/master/lib/internal/timers.js function Timeout(callback, after, args, isRepeat, isRefed) { after *= 1; // Coalesce to number or NaN if (!(after >= 1 && after <= TIMEOUT_MAX)) { // const TIMEOUT_MAX = 2 ** 31 - 1; if (after > TIMEOUT_MAX) { process.emitWarning(`${after} does not fit into` +' a 32-bit signed integer.' + '\nTimeout duration was set t 1.', 'TimeoutOverflowWarning'); } after = 1; // Schedule on next tick, follows browser behavior }
看過源代碼後,就知道node的處理策略了:若是delay=0,會設置爲1,註釋也說得很清楚了,是爲了遵循瀏覽器的行爲。es6
雖然不多用到,可是js中確是存在+0和-0的,那麼有什麼區別呢:github
+0 === -0; // true +0 === 0; // true -0 === 0; // true
能夠看到,經過全等比較,+0,-0和0都是相等的,那是否就能夠認爲這三者就是同樣的呢,還不能這麼輕易下結論,有時候頗有必要區分三者,那麼如何判斷呢,es6新增了一個方法Object.is(value1, value2),能夠用來判斷,具體效果以下:chrome
Object.is(0, -0); // false Object.is(+0, -0); // false Object.is(+0, 0); // true
這裏還須要說明的一點就是+0和0其實就是同樣的,由於+0等效Number(0),所以Object.is(+0, 0)是符合預期的,這裏順帶說一下Object.is的比較邏輯,根據MDN文檔描述,
Object.is()
方法判斷兩個值是否爲同一個值。若是知足如下條件則兩個值相等:瀏覽器
與==
運算不一樣。 ==
運算符在判斷相等前對兩邊的變量(若是它們不是同一類型) 進行強制轉換 (這種行爲的結果會將 "" == false
判斷爲 true
), 而 Object.is
不會強制轉換兩邊的值。
與===
運算也不相同。 ===
運算符 (也包括 ==
運算符) 將數字 -0
和 +0
視爲相等 ,而將Number.NaN
與NaN
視爲不相等.架構
最後來看下如何生成-0和+0吧:ide
1/-Infinity; // -0 0*-1; // -0 1/+Infinity; // +0 0*+1;// +0
因爲存在類型轉換,所以在判斷相等時,會有這樣的狀況:
'' == 0; // true [] == 0; // true +[] == 0; // true
這裏咱們說一下+[]的狀況,很容易理解,+至關於Number([]),最終會轉換成0,這沒什麼大不了,若是是下面這段代碼呢:
(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]]
其實表明的就是alert(1)
, http://www.jsfuck.com/ 這個奇葩網站專門幹這事的,原理就是使用的類型轉換,把咱們熟悉的代碼變成了這樣,真是騷操做。
font-size在css中使用頻繁,瀏覽器一般會默認設置成14px或者16px。若是設置成0呢?
.foo { font-size: 0; } <span class="foo">foo</span>
文字真的就沒有了,這符合預期,但若是設置的值小於12(非負),各瀏覽器處理稍有不一樣,chrome/edge瀏覽器會設置最小字體爲12px,firefox嚴格按照給定的值來顯示。
font-size:0的用處
在佈局過程當中,常常會生成空白字符,例如:
<div class="box1"> <span>a</span> <span>b</span> </div> <div class="box2"> <img src="xxx.jpg"> </div>
box1和box2高度實際上是略高於實際的內容的,並且box1的兩個span中間有間隙,沒有緊挨着,由於空白字符的緣由,引用css規範說明:On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element's font and line height properties. We call that imaginary box a "strut.",大意就是一個塊級容器元素內容區域由inline-level元素組成的;而這些linline-level元素被放在每一行的line-box裏面,line-box高度是由它全部子元素的高度計算得出的。瀏覽器會計算這一行裏每一個子元素的高度,再得出 line-box 的高度(具體來講就是從子元素的最高點到最低點的高度)。默認狀況下,一個 line-box 老是有足夠的高度來容納它的子元素,而每個行框能夠想象爲默認會有一個寬度爲0的空白節點,字體大小和行高會影響該節點,具體規範可查看 https://www.w3.org/TR/CSS2/visudet.html#line-height。
說完規範後,再來分析一下box1和box2的效果,爲了便於理解,下面的代碼手動加入了一個[x]
符號,表明strut:
<div class="box1"> <span>a</span> <span>b</span> [x] </div> <div class="box2"> <img src="xxx.jpg">[x] </div>
box1的兩個span發生了換行,至關於中間有個空格,所以會有間隙,若是span不換行,那麼中間的空隙也就沒有了。因爲存在[x]
,並且vertical-align:baseline的緣故,span/img和[x]
的baseline對齊以後,[x]
處於baseline如下的部分會撐開整個line-box的高度,所以會外部塊級容器的高度會略高一些,說得不清楚,咱們仍是上一張圖來講明吧:
粉色的線是圖片的baseline,紅色的線是strut的baseline,對齊以後strut的baseline下面還有一部分高度,box的最終高度就是img的頂部到strut底部之間的距離。分析完成因後,終於可使用font-size:0來解決問題了,在box上設置font-size:0後,strut就至關於沒有了,所以就不存在高度撐開的問題了,固然這裏還能夠改變img的vertical-align屬性來修復這個問題,好比img{ vertical-align:bottom; }那麼img的粉色線就跟strut的底部對齊了,也就不會撐開容器高度了,這裏說了box2,box1原理差很少,這裏涉及到vertical-align的知識了,可查閱https://www.w3.org/TR/CSS2/visudet.html#vertical-align 進行了解。
width和height也是能夠設置成0的,效果也是符合咱們預期的,但若是咱們的意圖是想經過設置0把元素隱藏的話,通常狀況下會採用以下方案:
.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; width: 1px; overflow: hidden; position: absolute; white-space: nowrap; }
有些屏幕閱讀器會忽略width和height等於0的元素,所以這裏特地設置成1px,固然關於元素的隱藏還有不少實現方案,有興趣可參考【1】;
line-height及行高,原意是baseline之間的高度,在css中就是一行的高度。默認狀況下,line-height是跟具體字體定義相關聯的,通常都是font-size的1.x倍,若是設置成0,在不一樣類型元素上的狀況是不同的,可分爲以下三種狀況:
1.)非置換行類元素
line-height定義的是最終參與計算line-box(行盒)的高度的值,而不會影響non-replaced inline element(非置換行類元素)的實際高度;
<style> .foo { line-height:0; } </style> <div> <span class="foo">a</span> // class爲foo的span高度不會受樣式影響 </div>
2.)行類塊級元素
會影響元素高度,若是line-height設置爲0,那麼該元素高度就變成了0,若是設置了height,那麼height將會起做用;
3.)塊級元素
當塊級元素包含inline-level(display:inline|inline-block)元素時, 行高定義的每個line-box(行盒)的最小高度,此外height也能影響塊級元素的最終高度,height比line-height有更高優先級,當沒有height狀況下,line-height起做用;
上面提到了line-box,若是有不瞭解的同窗,能夠看一下文末的連接【2】;
transform經常使用來作樣式變化和動畫,在有時候,會設置成以下形式:
transform: translateZ(0);
這實際上是爲了啓用GPU加速渲染,元素會單獨在一個繪製層(Layer)裏進行繪製,而不會對其餘層產生影響,所以也就少了不少計算和合成的功能,並且不會阻塞主線程,動畫會更加流暢,固然元素設置太多會致使性能下降,由於須要內存的維護。
【1】https://css-tricks.com/comparing-various-ways-to-hide-things-in-css/
【2】https://www.w3.org/TR/CSS2/visuren.html#line-box