什么是HTML <base>标签的build议?
我从来没有见过<base>
HTML标签实际上在任何地方使用。 它的使用有什么缺陷意味着我应该避免它?
我从来没有注意到它在现代生产网站(或任何网站)使用的事实让我感到震惊,虽然它似乎可能有用于简化我的网站上的链接的有用的应用程序。
编辑
使用基本标签几个星期后,我最终发现使用基本标签的一些主要陷阱,使它比最初出现的更不理想。 基本上,基本标签下href='#topic'
和href=''
的变化与默认行为是非常不兼容的,而且这种默认行为的变化很容易让第三方库在你的控制之外变得非常不可靠 ,因为它们在逻辑上将依赖于默认行为。 通常这些变化是微妙的,并且在处理大型代码库时导致不太明显的问题。 我从那以后创造了一个答案,详细说明了我所经历的问题。 因此,在您承诺广泛部署<base>
之前,请自行testing链接结果,这是我的新build议!
在决定是否使用<base>
标签之前,你需要了解它是如何工作的,它可以用于什么以及含义是什么,并最终超过其优点/缺点。
<base>
标签主要简化了在模板语言中创build相对链接,因为您不必担心每个链接中的当前上下文。
你可以做例如
<base href="${host}/${context}/${language}/"> ... <link rel="stylesheet" href="css/style.css" /> <script src="js/script.js"></script> ... <a href="home">home</a> <a href="faq">faq</a> <a href="contact">contact</a> ... <img src="img/logo.png" />
代替
<link rel="stylesheet" href="/${context}/${language}/css/style.css" /> <script src="/${context}/${language}/js/script.js"></script> ... <a href="/${context}/${language}/home">home</a> <a href="/${context}/${language}/faq">faq</a> <a href="/${context}/${language}/contact">contact</a> ... <img src="/${context}/${language}/img/logo.png" />
请注意, <base href>
值以斜杠结尾,否则将相对于最后一个path进行解释。
至于浏览器的兼容性,这只会导致IE中的问题。 <base>
标记在HTML中被指定为没有结束标记</base>
,因此仅使用<base>
而没有结束标记是合法的。 不过,IE6认为, <base>
标签之后的整个内容在这种情况下被放置在HTML DOM树的<base>
元素的子元素中。 这可能会导致第一眼看不到Javascript / jQuery / CSS中的不可解释的问题,即元素在特定的select器(如html>body
完全无法访问,直到您在HTML DOM检查器中发现中间应该有一个base
(和head
)。
一个常见的IE6修补程序正在使用IE条件注释来包含结束标记:
<base href="http://example.com/en/"><!--[if lte IE 6]></base><![endif]-->
如果您不关心W3 Validator,或者您已经使用了HTML5,那么您可以自行closures它,每个webbrowser都支持它:
<base href="http://example.com/en/" />
closures<base>
标记也立即修复了WinXP SP3上IE6的错误,在src
中以无限循环的方式请求<script>
资源。
当您在<base>
标记中使用相对URI(例如<base href="//example.com/somefolder/">
或<base href="/somefolder/">
时,将会显示另一个潜在的IE问题。 这将在IE6 / 7/8中失败。 然而,这不完全是浏览器的错。 在<base>
标签中使用相对URI是在它自己的错误。 HTML4规范声明它应该是一个绝对URI,因此从http://
或https://
scheme开始。 这已经在HTML5规范中被删除了。 因此,如果您仅使用HTML5并且仅支持与HTML5兼容的浏览器,那么通过在<base>
标记中使用相对URI,您应该会很好。
至于使用像<a href="#anchor">
这样的命名/哈希片段锚点,像<a href="?foo=bar">
这样的查询string锚点和像<a href="?foo=bar">
path片段锚点,通过<base>
标记,你基本上可以声明所有相对的链接, 包括那些锚点。 没有相对的链接是相对于当前的请求URI(如果没有<base>
标签)。 首先这可能会让初学者感到困惑。 要正确构build这些锚点,基本上需要包含URI,
<a href="${uri}#anchor">hash fragment</a> <a href="${uri}?foo=bar">query string</a> <a href="${uri};foo=bar">path fragment</a>
其中${uri}
基本上转换为PHP中的$_SERVER['REQUEST_URI']
,JSP中的${pageContext.request.requestURI}
以及JSF中的#{request.requestURI}
。 值得注意的是,像JSF这样的MVC框架使用标签来减less所有这些样板,并且不需要<base>
。 另请参阅ao 使用哪个URL链接/导航到其他JSF页面 。
基本标签效果的细分:
基本标签似乎有一些非直观的效果,我build议在依靠<base>
之前了解结果并自行testing! 由于我试图用基本标签处理本地网站,发现不同的url,只是发现了问题后的效果,我感到不得不为这些潜在的缺陷创build摘要。
我将在下面的例子中使用一个基本标签: <base href="http://www.example.com/other-subdirectory/">
作为我的例子,并假装代码所在的页面是http://localsite.com/original-subdirectory
重大的:
没有链接或命名的锚点或空白的hrefs将指向原始的子目录,除非明确指出:基本标记使一切链接不同,包括相同的页面锚点链接,而不是基本标记的url,例如:
-
<a href='#top-of-page' title='Some title'>A link to the top of the page via a named anchor</a>
变
<a href='http://www.example.com/other-subdirectory/#top-of-page' title='Some title'>A link to an #named-anchor on the completely different base page</a>
-
<a href='?update=1' title='Some title'>A link to this page</a>
变
<a href='http://www.example.com/other-subdirectory/?update=1' title='Some title'>A link to the base tag's page instead</a>
通过一些工作,您可以通过明确指定这些链接链接到他们所在的页面来解决这些问题,但是当您将第三方库添加到依赖标准行为的组合中时,很容易造成大乱。
次要:
IE6修复需要条件注释:需要ie6的条件注释,以避免搞砸dom层次,即<base href="http://www.example.com/"><!--[if lte IE 6]></base><![endif]-->
就像BalusC
在上面的回答中提到的那样。
所以总的来说,主要的问题会使用棘手的,除非你有完整的编辑控制每一个环节,正如我最初担心的那样,这使得它比它的价值更麻烦。 现在我必须重新写下所有的用法了! :p
在使用“片段”/散列时testing问题的相关链接:
http://www.w3.org/People/mimasa/test/base/
http://www.w3.org/People/mimasa/test/base/results
Izzy编辑:对于你们所有人来说,和我一样对这些评论感到困惑:
我刚刚testing了一下,结果如下:
- 尾随斜杠与否,对这里给出的例子没有任何影响(
#anchor
和?query
将简单地追加到指定的<BASE>
)。 - 然而它对相对链接有所不同:省略斜线,
other.html
和dir/other.html
将从DOCUMENT_ROOT
开始,给出的例子是[per which browser?] ,/other-subdirectory
被正确地视为文件从而省略[根据哪个浏览器?] 。
因此,对于相对链接, BASE
对移动的页面可以正常工作 – 而锚点和?queries
需要显式地指定文件名( BASE
有一个斜线,或者最后一个元素不对应于所用文件的名称) 。
可以把它看作是<BASE>
把文件本身的完整URL (而不是它所在的目录)replace<BASE>
,这样你就可以把事情做好。 假设这个例子中使用的文件是other-subdirectory/test.html
(移到新位置之后), 正确的规范应该是:
<base href="http://www.example.com/other-subdirectory/test.html
”>
– 等#anchor
, 一切都按预期工作: #anchor
, ?query
, other.html
, very/other.html
, very/other.html
/completely/other.html
very/other.html
。
好吧,等一下。 我不认为基地标签值得这个坏名声。
关于基本标签的好处是,它使您能够以较less的麻烦进行复杂的URL重写。
这是一个例子。 您决定将http://example.com/product/category/thisproduct转到http://example.com/product/thisproduct 。 您可以更改.htaccess文件,将第一个URL重写为第二个URL。
随着基地标签的地方,你做你的.htaccess重写,就是这样。 没问题。 但是如果没有base标签,所有的相对链接都会中断。
URL重写通常是必要的,因为调整它们可以帮助您的网站的架构和search引擎的可见性。 诚然,你需要解决人们提到的“#”和“”问题。 但是基本标签值得在工具包中占有一席之地。
要决定是否应该使用,你应该知道它是做什么的,是否需要。 这个答案已经部分概括了,我也对此作出了贡献。 但是为了更容易理解和遵循,在这里做第二个解释。 首先我们需要了解:
没有使用<BASE>
的浏览器如何处理链接?
对于一些例子,我们假设我们有这些URL:
A) http://www.example.com/index.html
B) http://www.example.com/
C) http://www.example.com/page.html
D) http://www.example.com/subdir/page.html
A + B都导致将相同的文件( index.html
)发送到浏览器,C当然发送page.html
,D发送/subdir/page.html
。
我们进一步假设,这两个页面都包含一组链接:
1)完全合格的绝对链接( http://www...
)
2)本地绝对链接( /some/dir/page.html
)
3)相关链接包括文件名( dir/page.html
)和
4)仅与“段”相关联( #anchor
, ?foo=bar
)。
浏览器接收该页面并呈现HTML。 如果find某个url,则需要知道该url指向哪个url。 链接1)总是清楚的,这是原样的。 所有其他人都依赖于渲染页面的URL:
URL | Link | Result --------+------+-------------------------- A,B,C,D | 2 | http://www.example.com/some/dir/page.html A,B,C | 3 | http://www.example.com/dir/page.html D | 3 | http://www.example.com/subdir/dir/page.html A | 4 | http://www.example.com/index.html#anchor B | 4 | http://www.example.com/#anchor C | 4 | http://www.example.com/page.html#anchor D | 4 | http://www.example.com/subdir/page.html#anchor
现在正在使用<BASE>
改变什么?
当浏览器显示 URL时, <BASE>
应该被replace。 所以它呈现所有链接,就像用户调用了<BASE>
指定的URL一样。 这解释了其他一些答案中的一些混淆:
- 再次,“完全合格的绝对链接”(“types1”)没有任何变化
- 对于本地绝对链接,目标服务器可能会更改(如果
<BASE>
指定的服务器与最初从用户调用的服务器不同) - 相对URL在这里变得至关重要,所以你必须特别注意你如何设置
<BASE>
:- 最好避免把它设置到一个目录 。 这样做,“types3”的链接可能会继续工作,但它肯定会打破“types4”的types(“情况B”除外)
- 将其设置为完全合格的文件名称 ,在大多数情况下会生成所需的结果。
一个例子最好的解释
假设你想使用mod_rewrite
来“美化”一些URL:
- 真正的文件:
<DOCUMENT_ROOT>/some/dir/file.php?lang=en
- 真实url:
http://www.example.com/some/dir/file.php?lang=en
:http://www.example.com/some/dir/file.php?lang=en
lang =http://www.example.com/some/dir/file.php?lang=en
- 用户友好的url:
http://www.example.com/en/file
:http://www.example.com/en/file
让我们假设mod_rewrite
用来透明地将用户友好的URL重写为真实的URL(无需外部redirect,所以“友好”的一个停留在浏览器地址栏中,而真实的一个被加载)。 现在做什么?
- 没有指定
<BASE>
:打破所有相关链接(因为它们现在基于http://www.example.com/en/file
) -
<BASE HREF='http://www.example.com/some/dir>
:绝对错误。dir
将被视为指定url的文件部分,所以相关链接仍然被破坏。 -
<BASE HREF='http://www.example.com/some/dir/>
:已经好了。 但“types4”的相关链接仍然被打破(“情况B”除外)。 -
<BASE HREF='http://www.example.com/some/dir/file.php>
:正确。 一切都应该与这一个。
最后一个音符
请记住,这适用于文档中的所有url:
-
<A HREF=
-
<IMG SRC=
-
<SCRIPT SRC=
- …
Drupal最初依赖于<base>
标签,后来由于HTTP爬虫和caching问题而决定不使用。
我一般不喜欢张贴链接。 但是这个实际上是值得分享的,因为它可以让那些正在寻找具有<base>
标签的真实世界体验的细节受益:
它使页面更容易离线查看; 您可以将完全限定的URL放在基本标记中,然后您的远程资源将正确加载。
散列“#”目前适用于与基本元素结合的跳转链接,但只适用于最新版本的Google Chrome和Firefox,而不适用于IE9。
IE9似乎会导致页面重新加载,而不会跳到任何地方。 如果您在iframe的外部使用跳转链接,同时指示框架在框架内的单独页面上加载跳转链接,您将获得框架内加载的跳转链接页面的第二个副本。
这可能不是很受欢迎,因为它不是很有名。 因为所有主stream浏览器都支持它,所以我不会害怕使用它。
如果您的网站使用AJAX,则需要确保所有网页的设置都正确,否则最终可能无法parsing链接。
只要不要在HTML 4.01 Strict页面中使用target
属性。
有一点要记住:
如果您开发的网页在iOS上的UIWebView中显示,那么您必须使用BASE标记。 否则就无法工作。 是JavaScript,CSS,图像 – 它们都不会在UIWebView下使用相对链接,除非指定了标签BASE。
以前我被这个抓到了,直到我发现了。
在页面内嵌SVG图像的情况下,使用base
标签时会出现另一个重要问题:
由于使用base
标记(如上所述),您将无法像使用相关的哈希URL那样使用它
<a href="#foo">
因为它们将根据基本URL而不是当前文档的位置来解决,因此不再是相对的。 所以你必须将当前文档的path添加到像这样的链接中
<a href="/path/to/this/page/name.html#foo">
因此, base
标记(即将长URL前缀远离锚标记并获得更好,更短的锚)的看似积极的方面之一完全不利于本地散列URL。
当在页面中内联SVG时,这是非常烦人的,无论是静态SVG还是dynamic生成的SVG,因为在SVG中可以有很多这样的引用,并且只要使用base
标记,它们都会中断,但大部分用户代理实现(至less在编写本文时,Chrome仍然可以在这些场景中运行)。
如果你正在使用模板系统或其他工具链来处理/生成你的页面,我总是会试图摆脱base
标签,因为就我所见,它给表格带来了更多的问题,而不是解决的问题。
我从来没有真正看到使用它的一点。 提供很less的优势,甚至可能使事情变得更难以使用。
除非你碰巧有几百或几千个链接,全部到相同的子目录。 那么它可能为您节省几个字节的带宽。
作为事后的想法,我似乎记得IE6中的标签存在一些问题。 您可以将它们放置在身体的任何地方,将网站的不同部分redirect到不同的位置。 这是固定在IE7,这打破了很多网站。
也有一个网站使用基地标签,并出现问题。 (升级jquery后),能够解决它的标签url如下所示:
<li><a href="{$smarty.server.REQUEST_URI}#tab_1"></li>
这使得他们“本地”
我使用的引用:
http://bugs.jqueryui.com/ticket/7822 http://htmlhelp.com/reference/html40/head/base.html http://tjvantoll.com/2013/02/17/using-jquery-ui-接片与-的基标签/
使用AngularJS时,BASE标签默默地打破了$ cookieStore,花了一段时间才弄清楚为什么我的应用程序不能再写入cookie了。 被警告…
我find了一种使用<base>
和基于锚的链接的方法。 您可以使用JavaScript来保持像#contact
这样的链接#contact
工作。 我用它在一些视差页面,它适用于我。
<base href="http://www.mywebsite.com/templates/"><!--[if lte IE 6]></base><![endif]--> ...content... <script> var pathname = window.location.href; $('a').each(function(){ var link = $(this).attr('href'); if(link.substr(0,1)=="#"){ $(this).attr('href', pathname + link); } }); </script>
你应该在页面的末尾使用
另外,你应该记住,如果你在非标准端口上运行你的web服务器,你也需要在href中包含端口号:
<base href="localhost:1234" />
基地href例子
说一个典型的链接页面:
<a href=home>home</a> <a href=faq>faq</a> <a href=etc>etc</a>
。并链接到一个diff文件夹:
..<a href=../p2/home>Portal2home</a> <a href=../p2/faq>p2faq</a> <a href=../p2/etc>p2etc</a>..
使用基础href ,我们可以避免重复基础文件夹:
<base href=../p2/> <a href=home>Portal2-Home</a> <a href=faq>P2FAQ</a> <a href=contact>P2Contact</a>
所以这是一个胜利.. 但页面也经常包含url来区分基础和目前的网页只支持一个基础href每页 ,所以赢得很快失去了作为基地∙hrefed重复,例如:
<a href=../p1/home>home</a> <a href=../p1/faq>faq</a> <a href=../p1/etc>etc</a> <!--.. <../p1/> basepath is repeated --> <base href=../p2> <a href=home>Portal2-Home</a> <a href=faq>P2FAQ</a> <a href=contact>P2Contact</a>
结论
( 基地目标可能是有用的。) 基地href是无用的:
- 页面同样是湿的,因为:
- 默认基地[-parent文件夹]&rlhar; 完美(除非不必要/罕有例外&Cscr; 1 &&Cscr; 2 )。
- 当前网页&rlhar; 不支持多个基础的hrefs 。
有关
- 与Apache∙重写库进行比较