为博客写文章时,有时会需要引用自己站点中的其他页面;而又有些时候,则会有需要引用外部的网站、资源等。但是在阅读文章时点开引用的链接之前,常常没有一个直观的方法来判断引用的资源是外部的还是内部的。因而,如果能有视觉上的提示能够在点开链接之前就区分这两种类型的链接,我觉得是很有帮助的。

维基百科为外部链接添加图标指示的例子

上面就是一个维基百科为外部链接添加图标指示的例子。可以看到图中绿框部分就是维基百科为外部链接添加的小图标,红框部分则是为 PDF 链接添加的图标指示,而普通的站内链接就只用了常规的蓝色字来表示。

实际上,要想实现这个功能也非常简单,我们可以使用 JS 来标记需要处理的元素(为其添加一个 class),随后用 CSS 添加相应样式即可。或者也可以仅使用 CSS 来实现,即使用合适的 CSS 选择器,并配上相应的样式

使用 JS 标记元素

通过 document.links,我们可以获得页面上所有的 <a> 元素;

通过 <a> 元素上的 hostname 属性与 location.hostname 比较,我们可以判断该链接是站内链接还是站外链接;

通过判定 <a> 元素上的 hostname 属性不为空,我们可以排除掉 mailto: 协议和 javascript: 协议的链接。

最终为过滤出的链接加上一个 class,如 external,就完成了对站外链接的标记。

document.addEventListener('DOMContentLoaded', function() {
  Array.prototype.filter.call(document.links, function(link) {
    return link.hostname && link.hostname !== location.hostname;
  })
      .forEach(function(link) {
        link.classList.add('external');
      });
});

如使用 jQuery,则可以使用如下代码:

jQuery(function($) {
  $(document.links)
      .filter(function() {
        return this.hostname && this.hostname !== location.hostname;
      })
      .each(function() {
        $(this).addClass('external');
      });
});

上面的代码示例中都使用了 hostname (仅包含域名)进行判断,根据需要也可以判断 host (包含域名和端口号)。

或使用 CSS 选择器选择元素

如果所有的站内链接都使用了相对链接(如 c/d.html, ./c/d.html, ../b/c/d.html, /a/b/c/d.html)的话,选择站外链接就只需:

a[href^="http://"], a[href^="https://"], a[href^="ftp://"], a[href^="//"] {}

而如果站内链接也使用了完整路径的话,除了上述规则,我们还需要额外的规则来匹配站内链接,并为其设置相应的样式规则来抵消上述规则中设置的样式。如:

a[href$="//zzz.buzz"], a[href*="//zzz.buzz/"] {}

具体规则如:

{
  /* 如使用 Icon Font 实现小图标 */
  content: unset;
  /* 如使用背景图片实现小图标 */
  background: unset;
  padding-right: unset;
}

如果要兼容不支持 unset 关键字的浏览器,如 IE, UC, QQ, Opera 等,则需要为每条属性写特定的规则,如:

{
  /* 如使用 Icon Font 实现小图标 */
  content: none;
  /* 如使用背景图片实现小图标 */
  background: transparent;
  padding-right: 0;
}

匹配 PDF 链接

此外,如果想要匹配 PDF 链接,可以使用如下选择器 (参照维基百科的 CSS 代码)

a[href$=".pdf"], a[href$=".PDF"],
a[href*=".pdf?"], a[href*=".PDF?"],
a[href*=".pdf#"], a[href$=".PDF#"] {

}

在能够选择我们需要处理的元素后,剩下的就是添加相应的样式规则了。根据要添加的小图标的实现方式不同,我们也需要不同的样式。

Icon Font

如使用了 Icon Font,则可以使用 ::after 伪元素来添加小图标。

/* 为外部链接添加图标指示 */
.external::after {
  /* 在 content 中设置图标字符 */
  /* !需根据使用的 Icon Font 设置为相应的字符 */
  content: 'open_in_new';
  /* 设置 Icon Font 字体 */
  /* !需根据使用的 Icon Font 设置为相应的字体 */
  font-family: 'Material Icons';
  /* 为图标设置合适的对齐方式 */
  vertical-align: text-bottom;
  /* 为图标设置合适的字体大小 */
  font-size: 14px;
  /* ... 更多设置 ... */
  /* 拷贝 Icon Font 附带的样式中的更多设置 */
}

/* 为 PDF 链接添加图标指示 */
a.external[href$=".pdf"]::after, a.external[href$=".PDF"]::after,
a.external[href*=".pdf?"]::after, a.external[href*=".PDF?"]::after,
a.external[href*=".pdf#"]::after, a.external[href$=".PDF#"]::after {
  content: 'picture_as_pdf';
}

图片

如小图标是一张图片,或 sprite 图的一部分,则需要类似如下样式:

/* 为外部链接添加图标指示 */
.external {
  /* 小图标的 url */
  background: url(//url/to/icon.png) center right no-repeat;
  /* 空出小图标的宽度 */
  padding-right: 14px;
}

/* 为 PDF 链接添加图标指示 */
a.external[href$=".pdf"], a.external[href$=".PDF"],
a.external[href*=".pdf?"], a.external[href*=".PDF?"],
a.external[href*=".pdf#"], a.external[href$=".PDF#"] {
  /* 小图标的 url */
  background: url(//url/to/icon.png) center right no-repeat;
  /* 空出小图标的宽度 */
  padding-right: 14px;
}

至此,为外部链接添加小图标就大功告成了。