我如何制作“标题” (工具提示、弹出窗口、替代文本)在 CSS 中与 SVG 一起使用,无需 JavaScript

发布于 2024-11-26 20:43:38 字数 1488 浏览 1 评论 0原文

在 SVG 中创建带有“title”属性的弹出窗口非常容易。但是如何用 CSS 达到同样的效果呢?

这是我为维基媒体制作的插图,我努力将其他维基百科人员想要在嵌入样式表中更正的大多数内容,其中样式属性按现实生活主题分组。大多数维基百科编辑都是电脑文盲,你不能指望他们会搜索大量代码来进行修改,如果他们必须更改代码中除了简单 CSS 值之外的任何内容,那么你可能会遇到一团糟。如果我让他们的可怜的大脑变得困难,那么迟早有人会使用 Inkscape、Illustrator 或其他一些同样可怕的矢量编辑器使该文件无法维护。

我可以使用 Javascript,但这会使插图更难以访问,并使代码对于需要编辑它的人来说更加混乱。此外,一些使用 Javascript 的 SVG 文件已从维基媒体中删除,但我不确定这是否是绝对规则。


当我验证我的文件时,我刚刚发现 SVG 中的标题属性在我使用它的地方是不允许的,但它适用于大多数浏览器。根据标准,您应该使用标题元素,但这似乎不适用于任何浏览器。另外,根据标准,我可以为样式元素赋予标题属性,但这似乎不适用于任何浏览器,并且需要我使用 180 个样式元素,而不是仅使用一个(代码是由脚本生成,所以创建它们对我来说不是问题,只是它会使代码变得更大并且更难以理解)。


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

不关心图像是否可以在 Inkscape 中编辑。 Inkscape 是创建位图图像的好工具(即使您必须通过其他程序运行它们以获得更好的压缩)。 Inkscape 不擅长创建 SVG 文件(或任何面向观众的基于矢量的图像文件,Inkscape 创建的基于矢量的图像文件仅对 Inkscape 有用),Inkscape 是一个非常非常差的工具选择创建作为最终产品的 SVG 图像; Sodipodi 是一个很好的工具,但 Inkscape 不是 Sodipodi,只是基于 Sodipodi(不幸的是,旧的 C 版本的 Sodipodi 在现代计算机系统上运行得不好,而且 C++ 版本从未完成)。 我想让我的图像易于使用文本编辑器进行编辑,这样维基百科就不会试图使用 Inkscape 并使文件变得难以维护(在此过程中,将大小从略小于 2 MB 增加到超过 60 MB,如果将其保存在 Inkscape 中作为“标准”SVG 图像(并不总是提供标准兼容文件),Inkscape 自己的基于 svg 的文件格式会生成更大的文件)。

我认为维基百科不允许在 SVG 图像中使用 javascript,因此 Javascript 是不可能的

我已经知道如何使用 javascript 创建工具提示以及在 SVG 中创建工具提示的两种不同方法(但不知道如何在 SVG 中嵌入 CSS)。除了原始问题中已经提到的原因之外,我不想在工具提示中使用 SVG 代码的原因是没有网络浏览器支持该标准,但 SVG 查看器支持(但不支持非标准)与浏览器一起使用的工具提示),因此手动更正文件中的工具提示(使用文本编辑器)的人将不得不在两个不同的位置更改文本,很可能随着时间的推移,导致查看时出现不同的工具提示在不同的浏览器/查看器。

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.

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.

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.


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).


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).

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

离鸿 2024-12-03 20:43:38

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

上。元素的直接父元素,并将文本内容加载到光标旁边显示的工具提示中。同时保留 InkScape 兼容性以及使用 InkScape 的“对象属性”对话框设置工具提示文本的能力。

给出以下示例 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>

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

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

给它一些样式:

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

然后插入少量 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>

警告: JS 块需要位于 SVG 文件的底部 - 如果您在 InkScape 中使用 XML 编辑器(罕见)它会弄乱脚本(这可以通过移动到外部 JS 文件并添加一些 DOM 就绪检测来解决)。

该方法还期望 a) all

元素应呈现为工具提示,并且 b) 只有<strong>一个</strong> <title>每个父元素都有一个元素(奇怪的是,SVG 规范允许多个元素)——这里我对其进行了硬编码,以简单地使用第一个 <title> 元素。遇到子元素,忽略任何后续子元素。

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

奖励:这可以很容易地扩展以利用元素也是如此,如果您需要带有更长文本的更复杂的工具提示。

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.

Given the following example 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:

<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).

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.

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.

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.

星星的軌跡 2024-12-03 20:43:38

据我所知你不能。
SVG 元素的行为似乎很奇怪。

我认为您可以使用 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>

但是 :after 选择器似乎不适用于 SVG 元素

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

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

I thought you could apply a similar concept as this using 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

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

假扮的天使 2024-12-03 20:43:38

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

包括你要求的:SVG+CSS。

基本上:

<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>

还有一些适当的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;
}

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

基本上:

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

使用这个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;}

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

更新:这对我来说在 Chrome v44 中工作正常,但在 Internet Explorer v9 中不行。
IE 只给我弹出窗口的标题,而不是弹出窗口本身。

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

Including what you asked for : 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:

.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.

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:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文