如何更好的使用css选择器充分发挥其性能

html-css017

如何更好的使用css选择器充分发挥其性能,第1张

CSS 选择器性能损耗来自?

CSS选择器对性能的影响源于浏览器匹配选择器和文档元素时所消耗的时间,所以优化选择器的原则是应尽量避免使用消耗更多匹配时间的选择器。而在这之前我们需要了解CSS选择器匹配的机制, 如子选择器规则:

#header >a {font-weight:blod}

我们中的大多数人都是从左到右的阅读习惯,会习惯性的设定浏览器也是从左到右的方式进行匹配规则,推测这条规则的开销并不高。

我们会假设浏览器以这样的方式工作:寻找 id 为 header 的元素,然后将样式规则应用到直系子元素中的 a 元素上。我们知道文档中只有一个 id 为 header 的元素,并且它只有几个 a 元素的子节点,所以这个CSS选择器应该相当高效。

事实上,却恰恰相反,CSS选择器是从右到左进行规则匹配。了解这个机制后,例子中看似高效的选择器在实际中的匹配开销是很高的,浏览器必须遍历页面中所有的 a 元素并且确定其父元素的 id 是否为 header 。

如果把例子的子选择器改为后代选择器则会开销更多,在遍历页面中所有 a 元素后还需向其上级遍历直到根节点。

#header a {font-weight:blod}

理解了CSS选择器从右到左匹配的机制后,明白只要当前选择符的左边还有其他选择符,样式系统就会继续向左移动,直到找到和规则匹配的选择符,或者因为不匹配而退出。我们把最右边选择符称之为关键选择器。

如何减少 CSS 选择器性能损耗?

Google 资深web开发工程师 Steve Souders 对 CSS 选择器的执行效率从高到低做了一个排序:

1.id选择器(#myid)

2.类选择器(.myclassname)

3.标签选择器(div,h1,p)

4.相邻选择器(h1+p)

5.子选择器(ul <li)

6.后代选择器(li a)

7.通配符选择器(*)

8.属性选择器(a[rel="external"])

9.伪类选择器(a:hover, li:nth-child)

根据以上「选择器匹配」与「选择器执行效率」原则,我们可以通过避免不恰当的使用,提升 CSS 选择器性能。

1、避免使用通用选择器

.content * {color: red}

浏览器匹配文档中所有的元素后分别向上逐级匹配 class 为 content 的元素,直到文档的根节点。因此其匹配开销是非常大的,所以应避免使用关键选择器是通配选择器的情况。

2、避免使用标签或 class 选择器限制 id 选择器

BAD

button#backButton {…}

BAD

.menu-left#newMenuIcon {…}

GOOD

#backButton {…}

GOOD

#newMenuIcon {…}

3、避免使用标签限制 class 选择器

BAD

treecell.indented {…}

GOOD

.treecell-indented {…}

BEST

.hierarchy-deep {…}

4、避免使用多层标签选择器。使用 class 选择器替换,减少css查找

BAD

treeitem[mailfolder="true"] >treerow >treecell {…}

GOOD

.treecell-mailfolder {…}

5、避免使用子选择器

BAD

treehead treerow treecell {…}

BETTER, BUT STILL BAD

treehead >treerow >treecell {…}

GOOD

.treecell-header {…}

6、使用继承

BAD

#bookmarkMenuItem >.menu-left { list-style-image: url(blah) }

GOOD

#bookmarkMenuItem { list-style-image: url(blah) }

思考

作为一名前端工程师,应该具有「提升 CSS 选择器性能」的意识,但实际应用中,是否需要完全贯彻这些原则呢?这是一个探索「追求高性能」与「可维护性」两者平衡的问题。

对于「淘宝」,每个页面的 DOM 元素超过1000个以上的网站来说,通过限制 CSS 选择器,改善性能是具有实际意义的。但对于普通网站,我更倾向于保证「语义化」和「可维护性」的前提下,提升 CSS 选择器性能。

1、打开Notepad++,新建一个文件

2、输入图中内容:

3、保存为:css.html,当然你也可以使用其它的名字,但扩展名需要使用.htm或.html

4、选择文件的保存位置,点击保存按钮

5、然后添加一个标签,输入一段用来测试的文字。

6、使用浏览器打开查看显示样式,现在还没有缩进。

7、接下来添加样式,这里我们使用内联样式,给P标签添加样式: style="text-indent:2em"

8、再刷新刚刚打开的网页看效果,是不是缩进了两个字符啊!

这里我们是使用em这个单位来缩进了两个字符,你也可以使用px作为单位来缩进指定的像素。

用HttpWebRequest和正则表达式提取网页中的链接

用HttpWebRequest取得网页源代码

Dim url As String=" http://www.sina.com "

Dim httpReq As System.Net.HttpWebRequest

Dim httpResp As System.Net.HttpWebResponse

Dim httpURL As New System.Uri(url)

httpReq = CType(WebRequest.Create(httpURL), HttpWebRequest)

httpReq.Method = "GET"

httpResp = CType(httpReq.GetResponse(), HttpWebResponse)

httpReq.KeepAlive = False \' 获取或设置一个值,该值指示是否与 Internet 资源建立持久连接。

Dim reader As StreamReader = _

New StreamReader(httpResp.GetResponseStream, System.Text.Encoding.GetEncoding("GB2312"))

Dim respHTML As String = reader.ReadToEnd() \'respHTML就是网页源代码

用正则表达式取得链接地址

Dim strRegex As String = "//([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?" \'这就是表达式

Dim r As System.Text.RegularExpressions.Regex

Dim m As System.Text.RegularExpressions.MatchCollection

r = New System.Text.RegularExpressions.Regex(strRegex, System.Text.RegularExpressions.RegexOptions.IgnoreCase) 

m = r.Matches(respHTML)

Dim i As Integer

For i = 0 To m.Count - 1

form1.DefInstance.ListBox1.Items.Add(m(i).Value) \'form1.DefInstance是form1的共享属性和实例

Next i

form1.DefInstance.ListBox.Visible = True \' 设置ListBox为可见

form1.DefInstance.ListBox.Sorted = True \' 对ListBox各元素进行排序

form1.DefInstance.ListBox1.Items.Add(m(i).Value) \'form1.DefInstance是form1的共享属性和实例, 共享成员如果是方法或属性,我们不用创建实例就可以直接用‘类名 .共享成员\'的方法进行调用。设置方法如下:

Private Shared m_vb6FormDefInstance As form1

Public Shared Property DefInstance() As form1

Get

If m_vb6FormDefInstance Is Nothing OrElse m_vb6FormDefInstance.IsDisposed Then \'判断窗体实例是否存在

m_vb6FormDefInstance = New form1

End If

DefInstance = m_vb6FormDefInstance

End Get

Set(ByVal Value As form1)

m_vb6FormDefInstance = Value

End Set

End Property

去除重复地址

Dim countForms As Integer \'以下代码去除重复地址

Dim lstForms() As String

Dim CurId As Integer

With formBrow.DefInstance.ListBox1

ReDim Preserve lstForms(0)

lstForms(0) = .Items(0) \'新数组的第一项和list的第一项相同

For countForms = 1 To .Items.Count - 1 \'items.count得到list1中的项目数

CurId = UBound(lstForms) \'curid为newlist中有项目数

If .Items(countForms) <>lstForms(CurId) Then \'如果旧表第二项不等于新表最大项

ReDim Preserve lstForms(CurId + 1) \'定位到新表第二项

lstForms(CurId + 1) = .Items(countForms) \'新表第二项等于旧表第二项

End If

Next countForms

.Ite ms.Clear() \'删除旧表所有项

For countForms = 0 To UBound(lstForms) \'把新表写入旧表

.Items.Add(lstForms(countForms))

Next countForms

End With

把地址导出为XML

可扩展标记语言 (XML) 是一种提供数据描述格式的标记语言。该语言使跨越多个平台进行更准确的内容声明和获得更有意义的搜索结果变得更加容易。此外,XML 实现了表示与数据的分离。例如,在 HTML 中,使用标记来告诉浏览器将数据显示为粗体或斜体;而在 XML 中,标记只用于描述数据,例如城市名、温度和大气压。在 XML 中,使用样式表(例如,可扩展样式表语言 (XSL) 和层叠样式表 (CSS))在浏览器中显示数据。XML 使数据与表示及处理分离开来,通过应用不同的样式表和应用程序,使您能够根据需要显示和处理数据。

XmlTextWriter 是 XmlWriter 类的实现,该类提供将 XML 写入文件、流或 TextWriter 的 API。该类有许多验证和检查规则,以确保所编写的 XML 的格式正确。当与某些规则发生冲突时,将会引发异常,并且这些异常应该被捕获。XmlTextWriter 有不同的构造函数,每个函数指定写入 XML 数据的不同类型的位置。下面代码使用的是将 XML 写入文件的构造函数。

首先使用 Formatting 属性指定正被编写的 XML 数据的格式。通过将此属性设置为 Indented,编写器使用 Indentation 和 IndentChar 属性缩进子元素。

代码显示了与每个 XML 节点类型相对应的 XML 编写方法。例如,编写一个元素将调用 WriteElementString 方法,编写一个属性将调用 WriteAttributeString 方法。对于嵌套级别,可以使用 WriteStartElement/WriteEndElement 对;如果要创建较复杂的属性,则可以使用 WriteStartAttribute/WriteEndAttribute 对。

请注意代码如何使用 WriteStartDocument 方法编写带版本号“1.0”的 XML 声明。如果要让编写器检查该文档的格式是否正确(先是 XML 声明,序言中的 DOCTYPE,只有一个根级别元素,等等),您必须在调用任何其他编写方法之前,调用此可选的 WriteStartDocument 方法。接着,此代码调用 WriteDocType 方法编写名为“urls”的文档类型。WriteDocType 调用中的第三个参数指定编写器将编写 SYSTEM“urls.dtd”。编写完成后,XML 文件指示有一个要根据其进行验证的外部 DTD。

最后,代码调用 Flush 方法将 XML 数据保存到文件,然后才调用 Close 方法。(虽然此示例确实只需要 Close 方法,但是也存在这样的情况,即需要保存所生成的 XML,并且需要重复使用编写器。)

要检查 XmlTextWriter 的输出,可通过用 XmlTextReader 读取生成的文件来执行往返测试,以验证 XML 的格式是正确的。

Private Sub saveXml()

Dim saveFileDialog1 As New SaveFileDialog

saveFileDialog1.Filter = "xml|*.xml"

saveFileDialog1.Title = "Save a xml File"

saveFileDialog1.ShowDialog()

If saveFileDialog1.FileName <>"" Then\'如果文件名不等于空白

Dim fileName As String = saveFileDialog1.FileName

If Not System.IO.File.Exists(fileName) Then  \'如果不存在同名文件

Dim myXmlTextWriter As XmlTextWriter = New XmlTextWriter(fileName, Nothing)

myXmlTextWriter.Formatting = System.Xml.Formatting.Indented\'设置缩进

myXmlTextWriter.WriteStartDocument(False)

myXmlTextWriter.WriteDocType("urls", Nothing, "urls.dtd", Nothing)

myXmlTextWriter.WriteComment("This file save the Urls")\'注释

myXmlTextWriter.WriteStartElement("urls")\'开始元素

myXmlTextWriter.WriteStartElement("url1", Nothing)\'开始元素

myXmlTextWriter.WriteAttributeString("now", Now) \'在属性里记录时间

For countAll As Integer = 0 To ListBox1.Items.Count - 1

Dim title As String = Strings.Right(ListBox1.Items.Item(countAll), 3)\'取URL后三字

Dim body As String = lstMuLu.Items.Item(countAll)

myXmlTextWriter.WriteElementString(title, Nothing, body)

Next

myXmlTextWriter.WriteEndElement()

myXmlTextWriter.WriteEndElement()

\'Write the XML to file and close the myXmlTextWriter

myXmlTextWriter.Flush()

myXmlTextWriter.Close()

End  If

End If

End Sub