Web fonts and extension for Azure App Service
在前端开发中,图标(Icon)是一种必不可少的资源文件。从最开始的png小图,到CSS Sprites,再到近些年的Font Awesome这类的图标字体文件,搭建一个简洁大方的网站越来越容易。我的博客使用Hexo框架,搭配Next主题,整体效果我也比较满意。但当我将其托管到Azure Website上时,却发现了两个404错误,提示找不到Font Awesome的两个字体文件。
我们抛开这个错误,先来说说字体文件以及计算机系统是如何显示字符的。
图标字体文件
首先介绍一款软件——FontForge,这是一个开源的字体编辑器。我们从Windows系统的字体文件夹(C:\Windows\Fonts\
)中随便找出一款中文字体,如微软雅黑,用FontForge
打开,点击CJK
区域的任意一个汉字,你会发现每个汉字其实就是一个矢量图形,整个字体文件就是一个以Unicode
为索引的图形表,Uicode值就是每个字符的编号。类似的,其它字符如英文字母、希腊字母也都是一个矢量图形。这也是这些字符放大后不会变得模糊的原因。
现在的字体文件通常是TTF(TrueType fonts)字体,例如我们上图所示的微软雅黑字体,它所表示的字库也叫做
矢量字库
。与矢量字库对应的就是点阵字库
了,它们的区别是早期没有图形接口的DOS系统、某些Linux终端或者一些嵌入式系统只能渲染点阵字体(Raster fonts,也称为光栅字体、位图字体),而且点阵字体放大后会变得模糊。
当我们知道字体文件就是一个图形库的索引表时,就能大致理解计算机系统是如何显示字符的了。首先我们的字符是存储在文件中,而负责处理文字的软件(Word、Notepad等)都会显式或隐式的使用一种编码方案来存储这些字符,例如ANSI、UTF-8、Unicode、GBK等等。然后当计算机系统要显式这些字符的时候,会读取这些编码值,结合当前使用的字体文件,使用这些编码值就可以在字体文件中找到对应的图形,最终这些图形通过显卡输出到图形显示器上。这也就解释了为什么当文件的编码方案设置错误时,就会出现乱码。
既然我们用到的各种字符(汉字、英文字母、阿拉伯数字等等)本质上是一个图形,为啥不把网站设计中常用的图标也放到字体文件中呢?于是Font Awesome、iconfont这之类的专门用于网页设计的图标字体应运而生。与此同时你会发现,当把图标看成是普通的文本后,font-size、color之类的文本修饰也能随手解决,再加上CSS3的支持,还能添加阴影、旋转等效果。
使用字体文件中的图标
在网页中使用Font Awesome
中的图标,只需要以下两个步骤:
- 引入CSS文件
1
<link href="/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
- 在
<i>
或<span>
中引入相关的class,例如:效果如下:1
2
3<i class="fa fa-home"></i>
<i class="fa fa-home" style="font-size:48px;"></i>
<i class="fa fa-home" style="font-size:60px;color:red;"></i>
Font Awesome 一般和内联元素搭配使用,因此
<i>
和<span>
常用于字体图标。
你不禁要问,这是如何办到的呢?答案就在Font Awesome
提供的CSS里面。
1 | @font-face { |
首先你会看到一个@font-face的声明,其中font-family属性定义了这个字体的名称,src属性定义了渲染该字体需要下载的字体文件。定义两个src以及一堆url是为了浏览器兼容性的需要,format属性告诉浏览器这个字体的格式,可选的字体格式有 woff、woff2、truetype、opentype、embedded-opentype、svg等。不同的浏览器支持不同的字体格式。
然后,在class fa中引用了这个字体,并且定义了一些基本属性。
1 | .fa { |
最后,对于每一个图标,定义了一个class,例如:
1 | .fa-home:before { |
这里,使用:before
在DOM中增加了一个伪元素
,使用反斜杠\
表示一个16进制数字,这个数字就是该图标在字体文件中的编码,也就是它的索引位置。
伪类(
Pseudo-classes
,使用一个冒号:
)与伪元素(Pseudo-elements
,使用两个冒号::
)是不一样的。但由于历史及CSS版本的原因,大多数浏览器同时支持用一个冒号:
或两个冒号::
来实现伪元素。
MIME Types
说完了字体和Font Awesome
,回到我们要解决的这个问题上来。Chrome的开发者工具报了两个404错误,提示下面两个文件找不到。
- fontawesome-webfont.woff
- fontawesome-webfont.woff2
很显然,这两个文件在服务器上一定是有的。Azure App Service背后使用的是IIS服务器,熟悉IIS的同学可能已经猜到了,这个是因为IIS上没有添加相应的MIME Types配置。IIS中的MIME Types配置用来指示哪些文件类型被视为静态文件,从而直接发送到客户端浏览器,而不是交给背后的CGI程序或者ISAPI扩展和过滤器来做动态处理。
Azure App Service现在支持运行在Linux系统中,因此背后的Web服务器就不是IIS了。我在创建App Service的时候,选择的是Windows系统,因此背后的Web服务器是IIS。
使用web.config
最显而易见的方式是配置web.config来让IIS支持这两种文件类型。
1 | <configuration> |
对于一个静态博客网站来说,添加一个web.config文件显得有些突兀,有点被入侵的感觉。并且对于每一个有这种问题的网站,都得添加一个web.config文件,太繁琐。有没有更好的办法呢?答案是使用Site Extension。
使用Site Extension
Azure Site Extension是App Service提供的一种平台接口,允许开发者或网站运营者对网站的运行环境做一些定制化和扩展。它的实现机制是使用XDT Transforms来修改ApplicationHost.config。ApplicationHost.config
是IIS7以上版本中的IIS配置文件,它包含了当前机器上所有的网站、应用程序、虚拟目录、应用程序池以及一些全局的服务器配置。我们平时使用的web.config,其实就是覆盖了这个文件中的部分配置信息。当然有一些重要的配置信息是无法被覆盖的。
使用XDT Transforms
来配置MIME Types也比较简单:
1 | <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> |
将上面的xml文件保存为applicationhost.xdt
,打开App Service对应的scm站点,将这个文件上传到SiteExtensions
目录下,重启App Service,改动就生效了。
如果你想把这个Site Extension分享给其他人,你需要将其打包成一个NuGet包,然后将其上传到Azure官方的托管平台上。具体步骤可以参考这篇文章:Writing a Site Extension for Azure Websites。
完整的代码在这里:https://github.com/johnnyqian/enable-font-awesome-site-extension
Site Extensions的托管
Site Extensions最开始的时候是托管在https://www.siteextensions.net上的。2018年2月份的时候,官方宣布将Site Extensions的托管迁移到https://www.nuget.org。原因是siteextensions.net
是个低流量的网站,不值得投入大量的运维成本,因此将其合并到nuget.org
。
熟悉.NET的同学应该对NuGet
不陌生,它是.NET生态系统中的包管理工具。类似的工具有很多,比如Java中的Maven,Node中的npm等。nuget.org
是托管NuGet包的一个在线网站,它已经成为.NET生态系统一个重要的组成部分,甚至.NET中的一些BCL类库也通过nuget.org
来发布,而不是跟随.NET Framework。
Site Extension的包发布到nuget.org
后,如何与其它常规的NuGet包区分开呢?答案是需要在nuspec中添加如下的改动:
1 | <tags>AzureSiteExtension</tags> |
我的这个FontAwesome的Site Extension在这两个托管平台都可以找到:
- https://www.siteextensions.net/packages/EnableFontAwesome/
- https://www.nuget.org/packages/EnableFontAwesome
在Azure Portal中,选择一个App Service,找到Extensions这个选项卡,点击添加,找到需要的Extension就可以了。
其它常用的Site Extensions
下面两个是我经常用到的Site Extensions。
1. HTTP to HTTPs
对于启用了全站HTTPS的网站来说,这个extension就是必须的了。当用户输入的是HTTP的URL时,这个extension会将URL重定向到以HTTPS开头。在添加Extensions的页面查找Redirect HTTP to HTTPS
可以找到这个extension。代码在这里:https://github.com/gregjhogan/redirect-http-to-https-site-extension
你也可以打开App Service对应的scm站点,搜索和安装extensions。
2. No-WWW
网站URL中的WWW前缀其实是一个历史问题,到底要不要带WWW前缀,是个有争议的问题。很多流行的站点已经不在其主站的URL中加上WWW前缀了,例如Twitter,Stack Overflow等。但是这个概念已经是根深蒂固了,许多人在输入URL的时候会输入WWW,因此我们需要将其重定向到不带WWW的域名地址(Bare Domain
)。作为一个博客网站,我倾向于使用不带WWW前缀的URL。在添加Extensions的页面查找Remove www domain prefix
可以找到这个extension。代码在这里:https://github.com/jamesharling/No-WWW
与此相反的是,很多大型的商业公司,例如Google,Microsoft,QQ等,它们的主站都是带WWW前缀的。当用户没有键入WWW前缀时,网站会将访问链接重定位到带WWW前缀的URL。目前nuget.org
上还没有人创建这样的extension,如果你有兴趣,可以尝试着创建它并将其上传到nuget.org
上。
不光是网站URL中的WWW有争议,连URL中http(s)之后的两道斜杠(
Forward Slashes
)都是多余的。“万维网之父”——蒂姆·伯纳斯-李(Tim Berners-Lee)坦言,当初设计时留下些许遗憾。例如,万维网的网址须以http(s)://
打头,伯纳斯-李认为,两道斜杠增加了用户的字符输入量(Berners-Lee ‘sorry’ for slashes),其实并没有必要。
总结
本文从我自己搭建Blog中遇到的两个404错误开始谈起,简单叙述了字体和图标字体的基本原理,以及如何在网页中使用FontAwesome这类的图标字体。最后谈到了使用Azure Site Extension来解决最开始的错误。希望对你在Azure平台上开发Web应用有所帮助。