整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          CSS新特性contain,控制頁(yè)面的重繪與重排

          CSS新特性contain,控制頁(yè)面的重繪與重排

          介紹新的 CSS 屬性 contain 之前,讀者首先需要了解什么是頁(yè)面的重繪與重排。

          之前已經(jīng)描述過(guò)很多次了,還不太了解的可以先看看這個(gè)提高 CSS 動(dòng)畫性能的正確姿勢(shì)。

          OK,下面進(jìn)入本文正題,

          contain 為何?

          contain 屬性允許我們指定特定的 DOM 元素和它的子元素,讓它們能夠獨(dú)立于整個(gè) DOM 樹結(jié)構(gòu)之外。目的是能夠讓瀏覽器有能力只對(duì)部分元素進(jìn)行重繪、重排,而不必每次都針對(duì)整個(gè)頁(yè)面。

          The contain property allows an author to indicate that an element and its contents are, as much as possible, independent of the rest of the document tree. This allows the browser to recalculate layout, style, paint, size, or any combination of them for a limited area of the DOM and not the entire page.

          contain 語(yǔ)法

          看看它的語(yǔ)法:

          {
            /* No layout containment. */
            contain: none;
            /* Turn on containment for layout, style, paint, and size. */
            contain: strict;
            /* Turn on containment for layout, style, and paint. */
            contain: content;
            /* Turn on size containment for an element. */
            contain: size;
            /* Turn on layout containment for an element. */
            contain: layout;
            /* Turn on style containment for an element. */
            contain: style;
            /* Turn on paint containment for an element. */
            contain: paint;
          }
          復(fù)制代碼

          除去 none,取值還有 6 個(gè),我們一個(gè)一個(gè)來(lái)看看。

          contain: size

          contain: size: 設(shè)定了 contain: size 的元素的渲染不會(huì)受到其子元素內(nèi)容的影響。

          The value turns on size containment for the element. This ensures that the containing box can be laid out without needing to examine its descendants.

          我開始看到這個(gè)定義也是一頭霧水,光看定義很難明白到底是什么意思。還需實(shí)踐一番:

          假設(shè)我們有如下簡(jiǎn)單結(jié)構(gòu):

          <div class="container">
             
          </div>
          復(fù)制代碼
          .container {
              width: 300px;
              padding: 10px;
              border: 1px solid red;
          }
          
          p {
              border: 1px solid #333;
              margin: 5px;
              font-size: 14px;
          }
          復(fù)制代碼

          并且,借助 jQuery 實(shí)現(xiàn)每次點(diǎn)擊容器添加一個(gè) <p>Coco</p> 結(jié)構(gòu):

          $('.container').on('click', e=> {
              $('.container').append('<p>Coco</p>')
          })
          復(fù)制代碼

          那么會(huì)得到如下結(jié)果:

          可以看到,容器 .container 的高度是會(huì)隨著元素的增加而增加的,這是正常的現(xiàn)象。

          此刻,我們給容器 .container 添加一個(gè) contain: size,也就會(huì)出現(xiàn)上述說(shuō)的:設(shè)定了 contain: size 的元素的渲染不會(huì)受到其子元素內(nèi)容的影響

          .container {
              width: 300px;
              padding: 10px;
              border: 1px solid red;
          +   contain: size
          }
          復(fù)制代碼

          再看看會(huì)發(fā)生什么:

          正常而言,父元素的高度會(huì)因?yàn)樽釉氐脑龆喽粨胃?,而現(xiàn)在,子元素的變化不再影響父元素的樣式布局,這就是 contain: size 的作用。

          contain: style

          接下來(lái)再說(shuō)說(shuō) contain: style、contain: layout 、contain: paint。先看看 contain: style。

          截止至本文書寫的過(guò)程中,contain: style 暫時(shí)被移除了。

          CSS Containment Module Level 1: Drop the at-risk “style containment” feature from this specification, move it Level 2。

          嗯,官方說(shuō)辭是因?yàn)榇嬖谀承╋L(fēng)險(xiǎn),暫時(shí)被移除,可能在規(guī)范的第二版會(huì)重新定義吧,那這個(gè)屬性也暫且放一放。

          contain: paint

          contain: paint:設(shè)定了 contain: paint 的元素即是設(shè)定了布局限制,也就是說(shuō)告知 User Agent,此元素的子元素不會(huì)在此元素的邊界之外被展示,因此,如果元素不在屏幕上或以其他方式設(shè)定為不可見,則還可以保證其后代不可見不被渲染。

          This value turns on paint containment for the element. This ensures that the descendants of the containing box don’t display outside its bounds, so if an element is off-screen or otherwise not visible, its descendants are also guaranteed to be not visible.

          這個(gè)稍微好理解一點(diǎn),先來(lái)看第一個(gè)特性:

          設(shè)定了 contain: paint 的元素的子元素不會(huì)在此元素的邊界之外被展示

          • 設(shè)定了 contain: paint 的元素的子元素不會(huì)在此元素的邊界之外被展示

          這個(gè)特點(diǎn)有點(diǎn)類似與 overflow: hidden,也就是明確告知用戶代理,子元素的內(nèi)容不會(huì)超出元素的邊界,所以超出部分無(wú)需渲染。

          簡(jiǎn)單示例,假設(shè)元素結(jié)構(gòu)如下:

          <div class="container">
              <p>Coco</p>
          </div>
          復(fù)制代碼
          .container {
              contain: paint;
              border: 1px solid red;
          }
          
          p{
              left: -100px;
          }
          復(fù)制代碼

          我們來(lái)看看,設(shè)定了 contain: paint 與沒(méi)設(shè)定時(shí)會(huì)發(fā)生什么:

          CodePen Demo -- contain: paint Demo

          設(shè)定了 contain: paint 的元素在屏幕之外時(shí)不會(huì)渲染繪制

          通過(guò)使用 contain: paint, 如果元素處于屏幕外,那么用戶代理就會(huì)忽略渲染這些元素,從而能更快的渲染其它內(nèi)容。

          contain: layout

          contain: layout:設(shè)定了 contain: layout 的元素即是設(shè)定了布局限制,也就是說(shuō)告知 User Agent,此元素內(nèi)部的樣式變化不會(huì)引起元素外部的樣式變化,反之亦然。

          This value turns on layout containment for the element. This ensures that the containing box is totally opaque for layout purposes; nothing outside can affect its internal layout, and vice versa.

          啟用 contain: layout 可以潛在地將每一幀需要渲染的元素?cái)?shù)量減少到少數(shù),而不是重新渲染整個(gè)文檔,從而為瀏覽器節(jié)省了大量不必要的工作,并顯著提高了性能。

          使用 contain:layout,開發(fā)人員可以指定對(duì)該元素任何后代的任何更改都不會(huì)影響任何外部元素的布局,反之亦然。

          因此,瀏覽器僅計(jì)算內(nèi)部元素的位置(如果對(duì)其進(jìn)行了修改),而其余DOM保持不變。因此,這意味著幀渲染管道中的布局過(guò)程將加快。

          存在的問(wèn)題

          描述很美好,但是在實(shí)際 Demo 測(cè)試的過(guò)程中(截止至2021/04/27,Chrome 90.0.4430.85),僅僅單獨(dú)使用 contain:layout 并沒(méi)有驗(yàn)證得到上述那么美好的結(jié)果。

          設(shè)定了 contain: layout 的指定元素,該元素的任何后代的任何更改還是會(huì)影響任何外部元素的布局,點(diǎn)擊紅框會(huì)增加一條 <p>Coco<p> 元素插入到 container 中:

          簡(jiǎn)單的代碼如下:

          <div class="container">
              <p>Coco</p>
              ...
          </div>
          <div class="g-test"></div>
          復(fù)制代碼
          html,
          body {
              width: 100%;
              height: 100%;
              display: flex;
              justify-content: center;
              align-items: center;
              flex-direction: column;
              gap: 10px;
          }
          
          .container {
              width: 150px;
              padding: 10px;
              contain: layout;
              border: 1px solid red;
          }
          
          .g-test {
              width: 150px;
              height: 150px;
              border: 1px solid green;
          }
          復(fù)制代碼

          CodePen Demo -- contain: layout Demo

          Can i Use -- CSS Contain

          截止至 2021-04-27,Can i Use 上的 CSS Contain 兼容性,已經(jīng)可以開始使用起來(lái):

          參考文獻(xiàn)

          • CSS Containment Module Level 1
          • CSS containment
          • CSS Containment in Chrome 52


          鏈接:https://juejin.cn/post/6958990366888607757
          來(lái)源:掘金

          SS的布局有太多種方式,元素的表現(xiàn)也有很多的形式。

          像我們熟悉的那些:行內(nèi)元素、塊元素、列表元素、表格元素、絕對(duì)定位、固定定位、浮動(dòng)、彈性布局、網(wǎng)格布局等等等等。

          一個(gè)元素的具體渲染可能會(huì)受到父子元素、兄弟元素的影響。

          大多數(shù)情況我們都可以通過(guò)一些手段,來(lái)解決我們遇到的布局或表現(xiàn)問(wèn)題。

          比如給一個(gè)元素賦予了浮動(dòng),那么可以通過(guò)清除浮動(dòng)來(lái)消除影響,再比如通過(guò)絕對(duì)定位來(lái)調(diào)整元素的位置,也可以通過(guò)padding或margin等避免其他元素被覆蓋。

          但是也有那么一些情況,我們不太好處理,比如某一個(gè)元素希望相對(duì)于它的父級(jí)區(qū)域做固定定位,而不是基于整個(gè)頁(yè)面,能做到嗎?再比如給定一個(gè)盒容器,無(wú)論子元素怎么排序布局或者浮動(dòng),也不會(huì)影響其他相鄰盒子的渲染,該怎么做到?

          其實(shí)不止這些,還有很多的實(shí)際場(chǎng)景讓我們很棘手,你是否在設(shè)計(jì)和實(shí)現(xiàn)方面做過(guò)平衡和妥協(xié)?

          對(duì)于現(xiàn)在的瀏覽器來(lái)說(shuō),所支持的CSS功能不允許我們說(shuō):我不行,我做不到。

          別的不說(shuō),今天要講的contain就能用來(lái)解決上面的問(wèn)題,它能做的事情還有很多,基于自身天然的屬性,甚至能輕松提升你的性能!

          contain概述

          contain表明該元素要獨(dú)立于頁(yè)面中的其他元素,該元素中的所有內(nèi)容都被局限在一個(gè)獨(dú)立的區(qū)域,跟其他元素隔離開來(lái),從而使得基于該元素的所有計(jì)算都是獨(dú)立的,被限制在該DOM子樹中,而不是整個(gè)頁(yè)面。這樣能夠讓頁(yè)面的性能提升。

          該元素構(gòu)成的容器,可以控制其產(chǎn)生的尺寸范圍、樣式作用域、布局方式、繪制區(qū)域。會(huì)生成新的包含區(qū)塊、新的層疊上下文、新的區(qū)塊格式化上下文。這些控制手段都對(duì)應(yīng)著不同的局限屬性,在容器內(nèi)對(duì)局限屬性的修改,不會(huì)影響容器外的部分,也就不會(huì)使得頁(yè)面經(jīng)常重新渲染,尤其在動(dòng)態(tài)修改頁(yè)面元素時(shí)會(huì)帶來(lái)更好的性能受益。

          我們理解它的時(shí)候,不要把它想成是包含的意思,理解成它的作用,是對(duì)包含內(nèi)容的一個(gè)局限,之后也會(huì)多次用到"局限"這個(gè)詞。

          分類

          一、關(guān)鍵詞

          通過(guò)關(guān)鍵詞,可以指定不同的局限屬性,從而產(chǎn)生不同的局限效果。

          1. none:不應(yīng)用任何局限。
          2. size:元素的尺寸無(wú)視子元素而單獨(dú)計(jì)算,在行向和塊向上都應(yīng)用該局限。
          3. inline-size:元素的尺寸無(wú)視子元素而單獨(dú)計(jì)算,只在行向上應(yīng)用該局限。
          4. layout:使得該元素的布局與元素外的任何內(nèi)容相互獨(dú)立,互不影響。即該元素所構(gòu)成的容器從頁(yè)面中隔離出來(lái),單獨(dú)計(jì)算布局。
          5. style:對(duì)于容器內(nèi)的某些可能影響外部屬性的值,被限制在容器內(nèi),不參與整體的計(jì)算,比如計(jì)數(shù)器和引號(hào)不會(huì)參與之前或者之后的計(jì)算,會(huì)有獨(dú)立的計(jì)算,對(duì)于外面來(lái)說(shuō)就好像這個(gè)元素沒(méi)存在過(guò)一樣,或者說(shuō)不知道有它的存在。
          6. paint:限制該元素的繪制區(qū)域范圍,子元素的渲染永遠(yuǎn)不會(huì)出現(xiàn)在容器外,容器的邊界限定了子元素的可見內(nèi)容。例如容器在屏幕外,那么就永遠(yuǎn)不用繪制,因?yàn)槠渥釉匾部隙ㄔ谄聊煌?,不像margin負(fù)值放在屏幕外那樣,子元素可能延伸到屏幕內(nèi)。
          7. content:相當(dāng)于設(shè)置了layout、paint、style,也就是除了size之外的所有值。
          8. strict:給該元素應(yīng)用所有局限規(guī)則,相當(dāng)于設(shè)置size、layout、paint、style。

          二、組合值

          也就是上面2-6關(guān)鍵字的任意組合,跟順序無(wú)關(guān),多個(gè)值之間用空格分隔開。跟個(gè)數(shù)也無(wú)關(guān),可以設(shè)置任意的數(shù)量。不過(guò)要注意,size和inline-size同時(shí)只能設(shè)置一個(gè),因?yàn)樗鼈z是沖突的。

          三、全局值

          全局值的作用,可以參考我在font-size那篇文章中的解釋說(shuō)明,它們的作用機(jī)制和原理都是一樣的,這里不在重復(fù)贅述。

          示例

          我們來(lái)對(duì)上面所說(shuō)的內(nèi)容,做一些示例,來(lái)看看它們的實(shí)際工作方式。

          先構(gòu)建一個(gè)基本的代碼,之后都以這個(gè)為基礎(chǔ)改造和演示:

          <div style="background-color: bisque;">
            我是父元素
            <div style="background-color: coral;">
              我是子元素
            </div>
          </div>
          <div style="background-color: lightpink;">
            我是父兄弟元素
          </div>

          看下現(xiàn)在的效果:

          效果

          記住這個(gè)效果,因?yàn)槲覀兘酉聛?lái)就要改變contain屬性,觀察它所發(fā)生的變化。

          1. 通過(guò)尺寸來(lái)控制
          <div style="contain: size;background-color: bisque;">
            我是父元素
            <div style="background-color: coral;">
              我是子元素
            </div>
          </div>
          <div style="background-color: lightpink;">
            我是父兄弟元素
          </div>

          給父元素加上contain:size樣式:

          效果

          可以看到,"我是父元素"和"我是父兄弟元素"重合了,也就說(shuō),父兄弟元素的渲染,直接從父元素渲染開始的位置開始渲染的。就好像父元素不存在一樣。

          這里面的奧妙通過(guò)控制臺(tái)看一下,其實(shí)就很容易解開了:

          效果

          就是因?yàn)楦冈氐母叨葹?了。在解釋之前先說(shuō)明一下,行向指的是我們書寫的方向,就是指的從左往右,你就可以理解成是多個(gè)行內(nèi)元素排列的方向,一直往后面追加的方向。塊向指的是我們折行的方向,也就是指的從上往下,你就可以理解成是多個(gè)塊級(jí)元素排列的方向,一直往下追加的方向。

          理解了這兩個(gè)之后,我們就知道,由于size影響著這兩個(gè)方向上的局限,它會(huì)變得無(wú)視子元素。因?yàn)槿绻麤](méi)有主動(dòng)設(shè)置尺寸的話,就好像子元素不存在一樣,那么它就沒(méi)有高度,所以兄弟元素就自然而然的頂上來(lái)了。

          這時(shí),我們改一下設(shè)置,讓它只在行向上有局限:

          <div style="contain: inline-size;background-color: bisque;">
            我是父元素
            <div style="background-color: coral;">
              我是子元素
            </div>
          </div>
          <div style="background-color: lightpink;">
            我是父兄弟元素
          </div>

          通過(guò)設(shè)置contain:inline-size:

          效果

          可以看到,效果又回來(lái)了,這是因?yàn)槲覀儧](méi)有在塊向上做局限,因此高度會(huì)自然撐開。

          既然說(shuō)到了這里,我們?cè)倏匆幌?,它是如何在行向上進(jìn)行局限的,構(gòu)造如下代碼:

          <div style="contain: inline-size;display: inline-block;background-color: bisque;">
            我是父元素
            <div style="background-color: coral;">
              我是子元素
            </div>
          </div>
          <div style="background-color: lightpink;">
            我是父兄弟元素
          </div>

          設(shè)置父元素為行內(nèi)塊,增加display:inline-block:

          效果

          瞬間又變成了這樣,這同樣是因?yàn)?,行?nèi)局限使得父元素獨(dú)立計(jì)算尺寸,而我們又沒(méi)手動(dòng)指定,因此它的寬度為0,子元素也跟著寬度為0,所以就變成了一個(gè)字一換行。

          這時(shí)即使你給子元素加上寬度,在行向上父元素也會(huì)無(wú)視你:

          效果

          你看我們給子元素加上100px的寬度,但是鼠標(biāo)查看父元素,依然是寬度為0。

          1. 通過(guò)布局來(lái)控制

          指定contain:layout,可以讓該元素獨(dú)立計(jì)算它的內(nèi)部布局,不受外界影響,我們先將子元素設(shè)定一個(gè)固定定位:

          <div style="background-color: bisque;">
            我是父元素
            <div style="position: fixed;top: 10px;background-color: coral;">
              我是子元素
            </div>
          </div>
          <div style="background-color: lightpink;">
            我是父兄弟元素
          </div>

          看下現(xiàn)在的效果:

          效果

          完全沒(méi)毛病,子元素固定到頁(yè)面頂部的10px位置。

          現(xiàn)在應(yīng)用一下我們的布局限制:

          <div style="contain: layout;background-color: bisque;">
            我是父元素
            <div style="position: fixed;top: 10px;background-color: coral;">
              我是子元素
            </div>
          </div>
          <div style="background-color: lightpink;">
            我是父兄弟元素
          </div>

          再看下顯示的效果:

          效果

          咦?明明是固定定位,它的位置卻是相對(duì)于父元素的。這就是布局限制的作用,相當(dāng)于父元素告訴頁(yè)面,從現(xiàn)在開始,這片的布局歸我管,所有的行為都向我請(qǐng)示,由我指揮。

          同樣,其他的position值,也都是基于父元素的布局限制來(lái)渲染的,這里就不做一一演示了。

          其實(shí),不光是position,只要是關(guān)于布局的,都會(huì)在此局限下生效,這里再演示一個(gè)浮動(dòng)的例子:

          <div style="height: 80px;padding: 5px;background-color: bisque;">
            <h2 style="margin-bottom: 7px;">我是父元素</h2>
            <p style="float: left;background-color: coral;">
              我是子元素
            </p>
          </div>
          <div style="height: 80px;padding: 5px;background-color: lightpink;">
            <h2>我是父兄弟元素</h2>
            <p style="background-color: coral;">
              我是父兄弟子元素
            </p>
          </div>

          兩個(gè)父元素各包含兩個(gè)子元素,其中第一個(gè)父元素的第二個(gè)子元素設(shè)置為左浮動(dòng),為了更好的演示,我把子元素改成了h2和p標(biāo)簽,看下現(xiàn)在的效果:

          效果

          父元素的兩個(gè)子元素正常顯示,但是父兄弟元素的第一個(gè)子元素里面的文字,被擠的偏移了,這是由于父元素的第二個(gè)子元素設(shè)置浮動(dòng)引起的,通過(guò)控制臺(tái)看下就明白了:

          效果

          紅線是我標(biāo)出來(lái)的,可以看到,父兄弟元素的h2和父元素的浮動(dòng)有一丁點(diǎn)的重合,導(dǎo)致文字被推開,這就是浮動(dòng)產(chǎn)生的影響。

          我們通過(guò)布局局限,來(lái)控制浮動(dòng)只發(fā)生在局限內(nèi),稍微改下代碼:

          <div style="contain: layout;height: 80px;padding: 5px;background-color: bisque;">
            <h2 style="margin-bottom: 7px;">我是父元素</h2>
            <p style="float: left;background-color: coral;">
              我是子元素
            </p>
          </div>
          <div style="height: 80px;padding: 5px;background-color: lightpink;">
            <h2>我是父兄弟元素</h2>
            <p style="background-color: coral;">
              我是父兄弟子元素
            </p>
          </div>

          給父元素添加了contain:layout,這是浮動(dòng)就不會(huì)影響后面的布局了:

          效果

          通過(guò)布局局限,我們可以把所有的關(guān)于布局的影響,都控制在容器內(nèi),這樣即使容器內(nèi)布局發(fā)生了改變,也完全不會(huì)影響頁(yè)面其他內(nèi)容,在動(dòng)態(tài)頁(yè)面中,如果需要頻繁的修改某些元素,通過(guò)這種方式管理和設(shè)計(jì)頁(yè)面,就能很有效的改善渲染的性能。

          1. 通過(guò)樣式來(lái)控制

          這里的樣式主要是針對(duì)計(jì)數(shù)器和引號(hào)的作用域,能控制它們只在所局限的范圍內(nèi)單獨(dú)計(jì)算,而不會(huì)影響全局的結(jié)果,就好像它們是單獨(dú)拿出來(lái)作為一個(gè)獨(dú)立的文檔一樣,看個(gè)例子:

          body {
            counter-reset: my-list;
          }
          div > div::before {
            counter-increment: my-list;
            content: "(" counter(my-list) "):";
          }
          <div>
            <div>第1行</div>
            <div>第2行</div>
            <div>第3行</div>
            <div>第4行</div>
            <div>第5行</div>
            <div>第6行</div>
          </div>

          我們?cè)O(shè)計(jì)這樣一個(gè)列表,通過(guò)自定義的計(jì)數(shù)器,設(shè)置一個(gè)前綴的顯示:

          效果

          如果我們希望第三行獨(dú)立出來(lái),進(jìn)行樣式局限,不參與外部計(jì)數(shù):

          <div>
            <div>第1行</div>
            <div>第2行</div>
            <div style="contain: style;">第3行</div>
            <div>第4行</div>
            <div>第5行</div>
            <div>第6行</div>
          </div>

          那么它就會(huì)展現(xiàn)成這個(gè)樣子:

          效果

          注意第三行的計(jì)數(shù),已經(jīng)重置為1,并且第四行從3開始,接著第二行的值繼續(xù)計(jì)數(shù)。

          1. 通過(guò)繪制來(lái)控制

          這個(gè)也比較厲害,就是父元素啥樣就是啥樣,子元素永遠(yuǎn)不會(huì)在容器外渲染:

          <div style="background-color: bisque;width: 100px;height: 100px;">
            <div>
            海客談瀛洲,煙濤微茫信難求。
            越人語(yǔ)天姥,云霞明滅或可睹。
            天姥連天向天橫,勢(shì)拔五岳掩赤城。
              </div>
          </div>

          有這樣一個(gè)代碼塊,容器的寬高為100px,內(nèi)容有超出部分:

          效果

          我們可以通過(guò)繪制局限來(lái)使容器外的內(nèi)容不顯示:

          <div style="contain: style;background-color: bisque;width: 100px;height: 100px;">
            <div>
            ??驼勫蓿瑹煗⒚P烹y求。
            越人語(yǔ)天姥,云霞明滅或可睹。
            天姥連天向天橫,勢(shì)拔五岳掩赤城。
            </div>
          </div>

          添加contain:paint,只讓繪制區(qū)域被限制在容器內(nèi)部:

          效果

          這個(gè)跟overflow:hidden有一點(diǎn)區(qū)別,就是繪制局限真的就是正常繪制,只不過(guò)不繪制容器外的部分,而hidden雖然隱藏,但是依然能通過(guò)js進(jìn)行滾動(dòng)。

          1. 通過(guò)組合值來(lái)控制

          我們也可以通過(guò)任意的值的組合來(lái)控制所需要的局限,也可以通過(guò)strict或content關(guān)鍵字來(lái)快速的做到這一點(diǎn)。這里就不再重復(fù)演示了

          最后

          合理的使用contain,不但能快速實(shí)現(xiàn)我們的需求,也能減少我們的修改量,而且會(huì)降低不理解現(xiàn)象的情況的出現(xiàn)頻率,更能提升頁(yè)面的性能。

          尤其是布局局限,提供給了我們更多的發(fā)揮空間,而且任意的復(fù)制到其他地方,也不會(huì)對(duì)外部元素有影響。

          每天一點(diǎn)小知識(shí),希望能夠幫助到你。

          hat about covers the basics of the mail function; now let’s really get fancy and explore mail headers and what we can do with them!

          上篇文章涵蓋了郵件功能的基本知識(shí);現(xiàn)在,讓我們真正開始想象和探索郵件標(biāo)題以及我們可以用它們做什么!

          HTML Email and Other Headers

          HTML電子郵件和其他頭信息

          So now you can send email from your PHP scripts. How exciting! Although I’m sure you’re already drunk with power, would you like to know how to send HTML email too? Of course you would!

          現(xiàn)在您可以從PHP腳本發(fā)送電子郵件了。多么令人興奮!雖然我肯定你已經(jīng)被權(quán)力迷住了,但你想知道如何發(fā)送HTML電子郵件嗎?你當(dāng)然會(huì)!

          To understand HTML email, first you need to understand mail headers. Any given email message is made up of two parts: the headers and the message body. Here’s how a simple message looks when your email program fetches it from your ISP:

          要理解HTML電子郵件,首先需要理解郵件頭信息。任何給定的電子郵件都由兩部分組成:頭信息和郵件正文。下面是當(dāng)您的電子郵件程序從ISP獲取簡(jiǎn)單郵件時(shí)的展現(xiàn):

          Return-Path: <sender@elsewhere.com>
          Delivered-To: you@some.net
          Received: ...several lines like this...
          From: Sender <sender@elsewhere.com>
          To: You <you@some.net>
          Subject: A Simple Message
          Date: Mon, 11 Feb 2002 16:08:19 -0500
          Organization: Sender's Company
          X-Mailer: Microsoft Outlook, Build 10.0.2616
          Hi there! <tap> <tap> Is this thing on?

          Everything up to the blank line makes up the headers for this message. In actual fact, most email messages will have many more header lines than this; however, to keep our focus I trimmed this example down to the bare essentials.

          到空白行的所有內(nèi)容構(gòu)成了該消息的標(biāo)頭。實(shí)際上,大多數(shù)電子郵件的頭信息都比這多很多;然而,為了保持我們的關(guān)注點(diǎn),我把這個(gè)例子縮減到了最基本的部分。

          As you can see, every line of the headers begins with the name of the header (From:, To:, Subject:, Date:, etc.), followed by some value. Most headers are standardized, and have a specific meaning, either to your mail program or to the mail servers that were responsible for getting the message to you. Non-standard headers exist as well, and they all begin with X- (e.g. X-Mailer:, a non-standard header, often appears to indicate the program that was used to send the message).

          如您所見,標(biāo)題的每一行都以標(biāo)題的名稱(From:、To:、Subject:、Date:,等等)開頭,后跟一些值。大多數(shù)郵件頭都是標(biāo)準(zhǔn)化的,對(duì)您的郵件程序或負(fù)責(zé)向您發(fā)送郵件的郵件服務(wù)器都有特定的含義。非標(biāo)準(zhǔn)標(biāo)頭也存在,它們都以X開頭(例如,X-Mailer:,一個(gè)非標(biāo)準(zhǔn)標(biāo)頭,通常顯示為指示用于發(fā)送消息的程序)。

          NOTE: If a header’s value needs more than one line, additional lines should begin with a space. We’ll see an example of this in the next section.

          如果標(biāo)頭的值需要多行,則其他行應(yīng)以空格開頭。我們將在下一節(jié)中看到一個(gè)例子。

          As soon as your mail program gets to a blank line, it knows the headers are over and the rest of the email is the message body, which it should display. In this case, the message body is the last line above.

          一旦你的郵件程序到達(dá)一個(gè)空行,它就知道郵件頭已經(jīng)結(jié)束,郵件的其余部分就是郵件正文,應(yīng)該顯示出來(lái)。在本例中,消息正文是上面的最后一行。

          PHP’s mail function lets you specify your own headers, which it adds to those it generates automatically to get your message where it needs to go. For example, the following call to the mail function will add an X-Mailer: header to the outgoing message, identifying PHP 4.x as the sending program:

          PHP的郵件功能允許您指定自己的郵件頭,并將其添加到自動(dòng)生成的郵件頭中,以便將郵件發(fā)送到需要的地方。例如,以下對(duì)mail函數(shù)的調(diào)用將向傳出消息添加一個(gè)X-Mailer:header,將PHP 4.X標(biāo)識(shí)為發(fā)送程序:

          <?php
          mail('recipient@some.net', 'Subject', 'Your message here.',
          'X-Mailer: PHP 4.x');
          ?>

          This optional fourth parameter is most often used to specify a ‘from’ address other than the default specified in php.ini. Let’s add a From: header to do just that:

          這個(gè)可選的第四個(gè)參數(shù)最常用于指定“from”地址,而不是php.ini中指定的默認(rèn)地址。讓我們添加一個(gè)From:header來(lái)實(shí)現(xiàn)這一點(diǎn):

          <?php
          mail('recipient@some.net', 'Subject', 'Your message here.',
          "From: sender@some.netnX-Mailer: PHP 4.x");
          ?>

          Note that since headers each appear on a single line, we must separate our two headers with a new line character (n), which means I need to use double quotes around the header string (single quoted strings don’t recognize special character codes like n).

          請(qǐng)注意,由于每個(gè)標(biāo)題都顯示在一行上,因此我們必須用新行字符(n)分隔兩個(gè)標(biāo)題,這意味著我需要在標(biāo)題字符串周圍使用雙引號(hào)(單引號(hào)字符串不能識(shí)別像n這樣的特殊字符代碼)。

          Additional headers also let you assign names to email addresses by specifying them in the format name <email>. Here’s our example again, but this time with names “The Sender” and “The Receiver” attached to the relevant addresses:

          其他標(biāo)題還允許您通過(guò)在格式名稱<email>中指定電子郵件地址來(lái)為其分配名稱。下面是我們的示例,但這一次在相關(guān)地址上附加了名稱“發(fā)件人”和“收件人”:

          <?php
          mail('recipient@some.net', 'Subject', 'Your message here.',
          "To: The Receiver <recipient@some.net>n" .
          "From: The Sender <sender@some.net>n" .
          "X-Mailer: PHP 4.x");
          ?>

          Notice that to do this, we’ve had to specify the To: header manually, since the first parameter of PHP’s mail function doesn’t support this more advanced address format. We must still list all the recipients of the message as bare email addresses in the first parameter, however.

          注意,要做到這一點(diǎn),我們必須手動(dòng)指定to:頭,因?yàn)镻HP郵件函數(shù)的第一個(gè)參數(shù)不支持這種更高級(jí)的地址格式。但是,我們?nèi)匀槐仨氃诘谝粋€(gè)參數(shù)中將郵件的所有收件人列為裸電子郵件地址。

          The cc: and Bcc: headers provide the ability to send carbon copies and blind carbon copies of a message as well:

          cc:和Bcc:標(biāo)頭還提供發(fā)送郵件的復(fù)寫副本和盲復(fù)寫副本的功能:

          <?php
          mail('recipient@some.net, someone@some.net, metoo@some.net',
          'Subject', 'Your message here.',
          "To: The Receiver <recipient@some.net>n" .
          "From: The Sender <sender@some.net>n" .
          "cc: Interested <someone@some.net>n" .
          "Bcc: Me Too <metoo@some.net>n" .
          "X-Mailer: PHP 4.x");
          ?>

          See how the email addresses of all recipients, be they actual addressees (To), carbon copies (Cc), or blind carbon copies (Bcc) are listed in the first parameter? This isn’t documented anywhere, but in my testing I’ve found that it’s absolutely vital if you want the message to get to everyone it’s supposed to, especially on Windows servers where PHP’s mail function is especially sensitive.

          查看如何在第一個(gè)參數(shù)中列出所有收件人的電子郵件地址,無(wú)論是實(shí)際收件人(收件人)、復(fù)寫副本(抄送)還是盲復(fù)寫副本(密件抄送)?這在任何地方都沒(méi)有文檔記錄,但在我的測(cè)試中,我發(fā)現(xiàn),如果希望消息傳遞給所有人,尤其是在PHP郵件功能特別敏感的Windows服務(wù)器上,這是絕對(duì)重要的。

          What does all this have to do with HTML email, you ask? Well, a few special headers will cause the message body to be interpreted as HTML by email clients that support it:

          你會(huì)問(wèn),這一切與HTML電子郵件有什么關(guān)系?好的,一些特殊的標(biāo)題將導(dǎo)致支持郵件正文的電子郵件客戶端將郵件正文解釋為HTML:

          <?php
          mail('recipient@some.net', 'Subject',
          '<html><body><p>Your <i>message</i> here.</p></body></html>',
          "To: The Receiver <recipient@some.net>n" .
          "From: The Sender <sender@some.net>n" .
          "MIME-Version: 1.0n" .
          "Content-type: text/html; charset=iso-8859-1");
          ?>

          Note both the message in HTML format as well as the two new headers: Mime-Version: and Content-type:.

          請(qǐng)注意HTML格式的消息以及兩個(gè)新標(biāo)頭:Mime-Version:和Content-type:。

          The MIME-Version: header indicates that the standard extended mail format will be used (MIME stands for Multipurpose Internet Mail Extensions), which allows for messages to be sent content types other than plain text. The Content-type: header then specifies that the message with contain HTML (and sets the character set to the standard for that format).

          MIME-Version:標(biāo)頭表示將使用標(biāo)準(zhǔn)的擴(kuò)展郵件格式(MIME代表多用途Internet郵件擴(kuò)展),它允許發(fā)送除純文本以外的內(nèi)容類型的郵件。然后,Content-type:頭指定消息包含HTML(并將字符集設(shè)置為該格式的標(biāo)準(zhǔn))。


          主站蜘蛛池模板: 国产一区二区三区久久| 视频在线观看一区二区三区| 3d动漫精品啪啪一区二区中 | 任你躁国语自产一区在| 成人区人妻精品一区二区不卡网站 | 国产亚洲一区二区三区在线观看 | 精品乱码一区内射人妻无码| 亚洲视频一区二区三区| 琪琪see色原网一区二区| 无码精品一区二区三区在线| 精品国产一区二区麻豆| 国产精品一区二区三区99| 亚洲AV无码一区二区三区在线| 日韩人妻无码一区二区三区99| 少妇特黄A一区二区三区| 大香伊人久久精品一区二区| 无码国产精品一区二区免费虚拟VR| 国产成人一区二区三区| 日本免费一区二区三区最新vr| 中文字幕在线无码一区| 一区二区三区四区精品视频| jazzjazz国产精品一区二区| 精品视频在线观看你懂的一区| 福利一区二区三区视频在线观看| 国产99视频精品一区| 亚洲a∨无码一区二区| 精品视频午夜一区二区| 国产无线乱码一区二三区| 精品一区二区ww| 成人精品视频一区二区三区不卡| 一区二区和激情视频| 国产美女露脸口爆吞精一区二区| 国产乱人伦精品一区二区 | 国产午夜毛片一区二区三区| 精品女同一区二区三区免费站| 国产MD视频一区二区三区| 无码播放一区二区三区| 丰满人妻一区二区三区免费视频 | 伊人色综合视频一区二区三区| 日本视频一区二区三区| 日韩精品无码一区二区中文字幕|