如何在CSS中创建一个“标题”(工具提示,弹出窗口,alt-text)以用于SVG,而无需JavaScript

时间:2023-01-14 23:21:36

It is pretty easy to create a pop-up with the "title" attribute in SVG. But how do you achieve the same effect with CSS.

使用SVG中的“title”属性创建弹出窗口非常容易。但是你如何用CSS实现同样的效果呢。

This is for an illustration I'm making for Wikimedia and I strive to have most things other wikipedians would like to correct within an embedded stylesheet, with style properties grouped by real-life subject. Most wikipedia editors are computer illiterates, you can't expected them to hunt through a lot of code to make their modifications and if they have to change anything but simple CSS-values within the code, then you probably get a nasty mess out of it. If I make this to hard for their poor brains, then sooner or later someone will make the file unmaintainable by using Inkscape, Illustrator or some other equally horrible vector editor.

这是我为维基媒*作的一个例子,我努力让其他维基人员想要在嵌入式样式表中纠正大部分内容,其中样式属性按现实主题分组。大多数*编辑都是计算机文盲,你不能指望他们通过大量代码进行修改以及如果他们必须在代码中改变除了简单的CSS值之外的任何东西,那么你可能会得到一个令人讨厌的混乱。如果我为他们可怜的大脑努力,那么迟早有人会使用Inkscape,Illustrator或其他同样可怕的矢量编辑器使文件无法维护。

I could use Javascript, but that would make the illustration less accessible and make the code even more confusing for people who need to edit it. Also, some SVG-files using Javascript have been removed from Wikimedia because of that, but I'm not sure if that is an absolute rule.

我可以使用Javascript,但这会使插图不易访问,并使代码更容易让需要编辑它的人感到困惑。此外,由于这一点,一些使用Javascript的SVG文件已从维基媒体中删除,但我不确定这是否是绝对的规则。


I just discovered when I validated my file that the title-attribute in SVG is not allowed where I have been using it, but it works with most browsers. According to the standard you should use the title-element, but that doesn't seem to work with any browsers. Also, according to the standard, I could give a title-attribute to a style-element, but that doesn't seem to work with any browser and it would require me to use 180 style-elements instead of just one (the code is generated by a script, so it isn't a problem for me to create them, it is just that it would make the code much larger and harder to understand).

我刚刚发现,当我验证我的文件时,SVG中的title-attribute不允许在我使用它的地方,但它适用于大多数浏览器。根据标准,您应该使用title-element,但这似乎不适用于任何浏览器。另外,根据标准,我可以给一个样式元素一个title-attribute,但这似乎不适用于任何浏览器,它需要我使用180个样式元素而不是一个(代码是由脚本生成,因此创建它们不是问题,只是它会使代码更大,更难理解)。


The two "answers" I've gotten thus far have not been for the question I asked, and is not even remotely useful.

到目前为止,我得到的两个“答案”并不是针对我提出的问题,甚至没有用处。

I don't care if the image is editable in Inkscape. Inkscape is a good tool for creating bitmap images (even if you have to run them through some other program to get better compression afterwards). Inkscape sucks at creating SVG files (or any vector based image files intended for an audience, the vector based image files Inkscape creates is only really usefull with Inkscape), Inkscape is a really, really, really poor tool to choose for creating SVG images intended as an end product; Sodipodi was a good tool for that, but Inkscape is not Sodipodi, only based on Sodipodi (unfortunatly, the old C-version of Sodipodi don't run well on modern computer systems and the C++ version was never finished). I want to make my image easy to edit with a text editor, so that no Wikipedian is tempted to use Inkscape and make the file unmaintanable (and in the process increase the size from slightly less then 2 MB to more then 60 MB, if you save it in Inkscape as a "standard" SVG image (which not always give a standard complient file), Inkscapes own svg-based file format makes even larger files).

我不在乎图像是否可以在Inkscape中编辑。 Inkscape是创建位图图像的好工具(即使你必须通过其他程序运行它们以便之后获得更好的压缩)。 Inkscape很难创建SVG文件(或任何面向观众的基于矢量的图像文件,Inkscape创建的基于矢量的图像文件只对Inkscape非常有用),Inkscape是一个非常非常非常糟糕的工具,可用于创建预期的SVG图像作为最终产品; Sodipodi是一个很好的工具,但是Inkscape不是Sodipodi,只是基于Sodipodi(不幸的是,Sodipodi的旧C版本在现代计算机系统上运行不佳而C ++版本从未完成)。我希望使用文本编辑器轻松编辑我的图像,这样就不会让*使用Inkscape并使文件无法管理(并且在此过程中将大小从略小于2 MB增加到超过60 MB,如果你将它作为“标准”SVG图像保存在Inkscape中(并不总是提供标准的兼容文件),Inkscapes自己的基于svg的文件格式可以生成更大的文件)。

I don't think wikipedia allow javascript within SVG-images, so Javascript is out of the question.

我不认为*允许在SVG图像中使用javascript,因此Javascript是不可能的。

I already know how to create tooltips with javascript and two different methods to create them in SVG (but not in CSS embedded in SVG). The reason, in addition to the one already mentioned in the original question, that I don't want to use SVG code for the tooltips is that no web-browser support the standard, but SVG-viewers do (but not the non-standard tooltips that work with browsers), so someone who would manually make corrections to a tooltip in the file (with a text editor), would have to change the text in two different places, most likely, with time, resulting in different tooltips when viewed in different browsers/viewers.

我已经知道如何使用javascript和两种不同的方法创建工具提示来在SVG中创建它们(但不是在SVG中嵌入的CSS中)。除了原始问题中已经提到的那个之外,我不想在工具提示中使用SVG代码的原因是没有Web浏览器支持标准,但SVG查看器(但不是非标准)与浏览器一起使用的工具提示),那么手动修改文件中工具提示(使用文本编辑器)的人必须在两个不同的地方更改文本,最有可能的是,随着时间的推移,在查看时会导致不同的工具提示在不同的浏览器/查看器中。

3 个解决方案

#1


4  

I often resort to using the (invalid) title="" attribute on SVG elements as it's so simple and seems to work in most browsers. I understand your requirement is that it is standards compliant and that people can edit the graphic in InkScape transparently and without breaking the tooltips - for this you will have to use some JavaScript. Here's a quick example I hope you'll find helpful, it will attach the mouseover event to each <title> element's immediate parent and load the text content in a tooltip displayed next to the cursor. This while retaining InkScape compatibility and the ability to use InkScape's "Object Properties" dialog box to set the tooltip text.

我经常使用SVG元素上的(无效)title =“”属性,因为它很简单,似乎适用于大多数浏览器。我理解你的要求是它符合标准,并且人们可以透明地编辑InkScape中的图形而不会破坏工具提示 - 为此你必须使用一些JavaScript。这是一个快速示例,我希望您会发现有用,它会将mouseover事件附加到每个

元素的直接父级,并将文本内容加载到光标旁边显示的工具提示中。这同时保留了InkScape兼容性并能够使用InkScape的“对象属性”对话框来设置工具提示文本。</p>

Given the following example SVG:

给出以下示例SVG:

<svg xmlns="http://www.w3.org/2000/svg">
  <title>Main Title</title>
  <g id="group1">
    <title>Title One</title>
    <circle cx="120" cy="60" r="40" fill="#993333" />
  </g>
  <g id="group2">
    <title>Title Two</title>
    <circle cx="60" cy="60" r="40" fill="#339933" />
    <g id="group3">
      <circle cx="180" cy="60" r="40" fill="#333399" />
      <title>Title Three</title>
    </g>
  </g>
</svg>

First add a dummy tooltip element:

首先添加一个虚拟工具提示元素:

<g id="toolTip" transform="translate(0,0)">
  <rect width="150" height="25" />
  <text x="5" y="18"> </text>
</g>

Give it some styling:

给它一些造型:

<style>
g#toolTip {
visibility: hidden;
}
  g#toolTip rect {
  fill: #FFCC00;
  }
  g#toolTip text {
  font-size: 16px;
  }
</style>

Then insert a sprinkling of JS:

然后插入一堆JS:

<script>
  <![CDATA[
  var toolTip = document.getElementById('toolTip');
  var titles = document.getElementsByTagName('title');
  for (var i = 0; i < titles.length; i++) {
    titles.item(i).parentNode.addEventListener('mouseover', function(e) {
      showTip(this,xy(e));
    }, true);
    titles.item(i).parentNode.addEventListener('mouseout', function() {
      hideTip();
    }, true);
  }
  function showTip(element,pos) {
    var text = element.getElementsByTagName('title')[0].childNodes[0].nodeValue;
    toolTip.getElementsByTagName('text')[0].childNodes[0].nodeValue = text;
    toolTip.setAttribute('transform', 'translate(' + pos + ')');
    toolTip.style.visibility = 'visible';
  }
  function hideTip() {
    toolTip.style.visibility = 'hidden';
  }
  function xy(e) {
    if (!e) var e = window.event;
    if (e.pageX || e.pageY) {
      return [e.pageX,e.pageY]
    } else if (e.clientX || e.clientY) {
      return [e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,e.clientY + document.body.scrollTop + document.documentElement.scrollTop];
    }
    return [0,0]
  }
  ]]>
</script>

Caveats: The JS block needs to go at the bottom of the SVG file - and if you use the XML editor in InkScape (rare) it will mess up the script (this may be solved by moving to an external JS file and adding some DOM ready detection).

注意事项:JS块需要放在SVG文件的底部 - 如果你在InkScape中使用XML编辑器(很少见),它会搞乱脚本(这可以通过转移到外部JS文件并添加一些DOM来解决)准备好检测)。

The approach also expects that a) all <title> elements should be rendered as tooltips and b) that there is only ever one <title> element per parent (oddly, the SVG spec allows multiple) - here I have hard coded it to simply use the first <title> child element encountered, ignoring any subsequent ones.

该方法还期望a)所有

元素应该被渲染为工具提示,并且b)每个父级只有一个 元素(奇怪的是,SVG规范允许多个) - 这里我将其硬编码为简单使用遇到的第一个 子元素,忽略任何后续元素。</p>

Note: the xy(e) function is only needed to get round browser inconsistencies when it comes to reporting the cursor position - you may not need it, or you may prefer to roll your own.

注意:xy(e)函数只需要在报告光标位置时解决浏览器不一致问题 - 您可能不需要它,或者您可能更喜欢自己滚动。

Bonus: This could easily be extended to make use of the <desc> element as well, should you need more elaborate tooltips with longer bits of text.

额外奖励:如果您需要更长篇文本的更复杂的工具提示,这可以很容易地扩展到使用 元素。

#2


1  

As far as i can tell you can't. The SVG element seems to behave oddly.

据我所知,你不能。 SVG元素似乎表现得很奇怪。

I thought you could apply a similar concept as this using CSS3:

我认为你可以使用CSS3应用类似的概念:

<style type="text/css">
acronym{
    position:relative
}
acronym:after {
    content:attr(title);
    position:absolute;
    position:absolute;
    left:100%;
    margin-left:-10px;
    top:-0.5em;
    z-index:2;
    padding:0.25em;
    width:200px;
    background-color:#f1f1f1;
    text-align:center;
    display:none;   
}
acronym:hover:after{
    display:block;
}
</style>

<acronym title="Keep It Simple Stupid"><a href="/">KISS</a></acronym>

But the :after Selector doesn't seem to work on the SVG element

但是:在Selector之后似乎不适用于SVG元素

I think your best bet is a jQuery script which runs on $(document).ready() and does all the heavy lifting for you.

我认为你最好的选择是在$(document).ready()上运行的jQuery脚本,并为你完成所有繁重的工作。

#3


0  

This article: http://codepen.io/recursiev/pen/zpJxs demonstrates several types of tooltip with SVG.

本文:http://codepen.io/recursiev/pen/zpJxs演示了几种带SVG的工具提示。

Including what you asked for : SVG+CSS.

包括你要求的内容:SVG + CSS。

Basically:

<g class="tooltip css" transform="translate(200,50)">
    <rect x="-3em" y="-45" width="6em" height="1.25em"/>
    <text y="-45" dy="1em" text-anchor="middle" fill="LightSeaGreen">
        SVG/CSS Tip</text>
</g>

With some appropriate CSS as well:

还有一些合适的CSS:

.tooltip {
    pointer-events:none; /*let mouse events pass through*/
    opacity:0;
    transition: opacity 0.3s;
    text-shadow:1px 1px 0px gray;
}
g.tooltip:not(.css) {
    fill:currentColor;
}
g.tooltip rect {
    fill: lightblue;
    stroke: gray;
}

This article: http://www.scientificpsychic.com/etc/css-mouseover.html demonstrates CSS only tooltips.

本文:http://www.scientificpsychic.com/etc/css-mouseover.html演示了仅CSS工具提示。

basically:

<span class="dropt" title="Title for the pop-up">Hot Zone Text
    <span style="width:500px;">Pop-up text</span>
</span>

with this CSS:

用这个CSS:

span.dropt {border-bottom: thin dotted; background: #ffeedd;}
span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; }
span.dropt span {position: absolute; left: -9999px;
  margin: 20px 0 0 0px; padding: 3px 3px 3px 3px;
  border-style:solid; border-color:black; border-width:1px; z-index: 6;}
span.dropt:hover span {left: 2%; background: #ffffff;} 
span.dropt span {position: absolute; left: -9999px;
  margin: 4px 0 0 0px; padding: 3px 3px 3px 3px; 
  border-style:solid; border-color:black; border-width:1px;}
span.dropt:hover span {margin: 20px 0 0 170px; background: #ffffff; z-index:6;}

Between these, you should be able to get exactly what you want.

在这些之间,你应该能够得到你想要的。

UPDATE: This works fine for me in Chrome v44, but not in Internet Explorer v9. IE just gives me the popup's title, not the popup itself.

更新:这适用于我在Chrome v44中,但不适用于Internet Explorer v9。 IE只是给了我弹出窗口的标题,而不是弹出窗口本身。

#1


4  

I often resort to using the (invalid) title="" attribute on SVG elements as it's so simple and seems to work in most browsers. I understand your requirement is that it is standards compliant and that people can edit the graphic in InkScape transparently and without breaking the tooltips - for this you will have to use some JavaScript. Here's a quick example I hope you'll find helpful, it will attach the mouseover event to each <title> element's immediate parent and load the text content in a tooltip displayed next to the cursor. This while retaining InkScape compatibility and the ability to use InkScape's "Object Properties" dialog box to set the tooltip text.

我经常使用SVG元素上的(无效)title =“”属性,因为它很简单,似乎适用于大多数浏览器。我理解你的要求是它符合标准,并且人们可以透明地编辑InkScape中的图形而不会破坏工具提示 - 为此你必须使用一些JavaScript。这是一个快速示例,我希望您会发现有用,它会将mouseover事件附加到每个

元素的直接父级,并将文本内容加载到光标旁边显示的工具提示中。这同时保留了InkScape兼容性并能够使用InkScape的“对象属性”对话框来设置工具提示文本。</p>

Given the following example SVG:

给出以下示例SVG:

<svg xmlns="http://www.w3.org/2000/svg">
  <title>Main Title</title>
  <g id="group1">
    <title>Title One</title>
    <circle cx="120" cy="60" r="40" fill="#993333" />
  </g>
  <g id="group2">
    <title>Title Two</title>
    <circle cx="60" cy="60" r="40" fill="#339933" />
    <g id="group3">
      <circle cx="180" cy="60" r="40" fill="#333399" />
      <title>Title Three</title>
    </g>
  </g>
</svg>

First add a dummy tooltip element:

首先添加一个虚拟工具提示元素:

<g id="toolTip" transform="translate(0,0)">
  <rect width="150" height="25" />
  <text x="5" y="18"> </text>
</g>

Give it some styling:

给它一些造型:

<style>
g#toolTip {
visibility: hidden;
}
  g#toolTip rect {
  fill: #FFCC00;
  }
  g#toolTip text {
  font-size: 16px;
  }
</style>

Then insert a sprinkling of JS:

然后插入一堆JS:

<script>
  <![CDATA[
  var toolTip = document.getElementById('toolTip');
  var titles = document.getElementsByTagName('title');
  for (var i = 0; i < titles.length; i++) {
    titles.item(i).parentNode.addEventListener('mouseover', function(e) {
      showTip(this,xy(e));
    }, true);
    titles.item(i).parentNode.addEventListener('mouseout', function() {
      hideTip();
    }, true);
  }
  function showTip(element,pos) {
    var text = element.getElementsByTagName('title')[0].childNodes[0].nodeValue;
    toolTip.getElementsByTagName('text')[0].childNodes[0].nodeValue = text;
    toolTip.setAttribute('transform', 'translate(' + pos + ')');
    toolTip.style.visibility = 'visible';
  }
  function hideTip() {
    toolTip.style.visibility = 'hidden';
  }
  function xy(e) {
    if (!e) var e = window.event;
    if (e.pageX || e.pageY) {
      return [e.pageX,e.pageY]
    } else if (e.clientX || e.clientY) {
      return [e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,e.clientY + document.body.scrollTop + document.documentElement.scrollTop];
    }
    return [0,0]
  }
  ]]>
</script>

Caveats: The JS block needs to go at the bottom of the SVG file - and if you use the XML editor in InkScape (rare) it will mess up the script (this may be solved by moving to an external JS file and adding some DOM ready detection).

注意事项:JS块需要放在SVG文件的底部 - 如果你在InkScape中使用XML编辑器(很少见),它会搞乱脚本(这可以通过转移到外部JS文件并添加一些DOM来解决)准备好检测)。

The approach also expects that a) all <title> elements should be rendered as tooltips and b) that there is only ever one <title> element per parent (oddly, the SVG spec allows multiple) - here I have hard coded it to simply use the first <title> child element encountered, ignoring any subsequent ones.

该方法还期望a)所有

元素应该被渲染为工具提示,并且b)每个父级只有一个 元素(奇怪的是,SVG规范允许多个) - 这里我将其硬编码为简单使用遇到的第一个 子元素,忽略任何后续元素。</p>

Note: the xy(e) function is only needed to get round browser inconsistencies when it comes to reporting the cursor position - you may not need it, or you may prefer to roll your own.

注意:xy(e)函数只需要在报告光标位置时解决浏览器不一致问题 - 您可能不需要它,或者您可能更喜欢自己滚动。

Bonus: This could easily be extended to make use of the <desc> element as well, should you need more elaborate tooltips with longer bits of text.

额外奖励:如果您需要更长篇文本的更复杂的工具提示,这可以很容易地扩展到使用 元素。

#2


1  

As far as i can tell you can't. The SVG element seems to behave oddly.

据我所知,你不能。 SVG元素似乎表现得很奇怪。

I thought you could apply a similar concept as this using CSS3:

我认为你可以使用CSS3应用类似的概念:

<style type="text/css">
acronym{
    position:relative
}
acronym:after {
    content:attr(title);
    position:absolute;
    position:absolute;
    left:100%;
    margin-left:-10px;
    top:-0.5em;
    z-index:2;
    padding:0.25em;
    width:200px;
    background-color:#f1f1f1;
    text-align:center;
    display:none;   
}
acronym:hover:after{
    display:block;
}
</style>

<acronym title="Keep It Simple Stupid"><a href="/">KISS</a></acronym>

But the :after Selector doesn't seem to work on the SVG element

但是:在Selector之后似乎不适用于SVG元素

I think your best bet is a jQuery script which runs on $(document).ready() and does all the heavy lifting for you.

我认为你最好的选择是在$(document).ready()上运行的jQuery脚本,并为你完成所有繁重的工作。

#3


0  

This article: http://codepen.io/recursiev/pen/zpJxs demonstrates several types of tooltip with SVG.

本文:http://codepen.io/recursiev/pen/zpJxs演示了几种带SVG的工具提示。

Including what you asked for : SVG+CSS.

包括你要求的内容:SVG + CSS。

Basically:

<g class="tooltip css" transform="translate(200,50)">
    <rect x="-3em" y="-45" width="6em" height="1.25em"/>
    <text y="-45" dy="1em" text-anchor="middle" fill="LightSeaGreen">
        SVG/CSS Tip</text>
</g>

With some appropriate CSS as well:

还有一些合适的CSS:

.tooltip {
    pointer-events:none; /*let mouse events pass through*/
    opacity:0;
    transition: opacity 0.3s;
    text-shadow:1px 1px 0px gray;
}
g.tooltip:not(.css) {
    fill:currentColor;
}
g.tooltip rect {
    fill: lightblue;
    stroke: gray;
}

This article: http://www.scientificpsychic.com/etc/css-mouseover.html demonstrates CSS only tooltips.

本文:http://www.scientificpsychic.com/etc/css-mouseover.html演示了仅CSS工具提示。

basically:

<span class="dropt" title="Title for the pop-up">Hot Zone Text
    <span style="width:500px;">Pop-up text</span>
</span>

with this CSS:

用这个CSS:

span.dropt {border-bottom: thin dotted; background: #ffeedd;}
span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; }
span.dropt span {position: absolute; left: -9999px;
  margin: 20px 0 0 0px; padding: 3px 3px 3px 3px;
  border-style:solid; border-color:black; border-width:1px; z-index: 6;}
span.dropt:hover span {left: 2%; background: #ffffff;} 
span.dropt span {position: absolute; left: -9999px;
  margin: 4px 0 0 0px; padding: 3px 3px 3px 3px; 
  border-style:solid; border-color:black; border-width:1px;}
span.dropt:hover span {margin: 20px 0 0 170px; background: #ffffff; z-index:6;}

Between these, you should be able to get exactly what you want.

在这些之间,你应该能够得到你想要的。

UPDATE: This works fine for me in Chrome v44, but not in Internet Explorer v9. IE just gives me the popup's title, not the popup itself.

更新:这适用于我在Chrome v44中,但不适用于Internet Explorer v9。 IE只是给了我弹出窗口的标题,而不是弹出窗口本身。