📜 ⬆️ ⬇️

Problems using SVG buttons in browsers

This article is a continuation of the article. We draw a button in SVG , in which the problems of creating SVG images for use as buttons on web pages were considered. Here I will go directly to the implementation of the received images in the HTML code and tell you what problems the developer will face, how these problems can be solved and what to do with the problems that cannot be solved.

Just in case (for those who did not read the first article) I will repeat that many of the problems were not solved and that in the end forced me to abandon the idea of ​​using SVG. So if you don’t want to waste time reading an article that doesn’t lead to a real-life result, you can easily skip it. Those who despite this are interesting details and specifics, I ask under the cat.

Insert button on the page

There are five ways to add an SVG image to an HTML page:
  1. <object> tag ;
  2. <iframe> tag ;
  3. <embed> tag ;
  4. <img> tag ;
  5. CSS style background .
Rummaging through the Internet in search of information about SVG, I came across a page where all these methods are put together to test their work in different browsers. I tested in Opera 10.63 and 11.00, Firefox 3.6.13, Chrome 8.0.552.224. IE I did not include in this list, because the latest stable version of SVG is not supported. I planned to first deal with the rest of the browsers, and if everything went well, install an additional plugin for SVG support in IE and test its behavior, as well as play around with the ninth version that is currently being developed. But this did not happen, because (as already mentioned), even with browsers that officially support SVG, too many problems came up. Spending extra time now on checking IE just for the sake of including the results in an article is considered irrational. I apologize to the fans of this browser, if any, will meet among readers. As well as fans of other browsers that are not on my list.

So, as a result of the check, we got the following picture:
It turns out that Firefox spoils us with all the raspberries. For our purposes, neither embedded scripts nor internal processing of events in SVG are needed: everything you need can be done in the HTML file itself (moreover, in some aspects it would be much more convenient), so the picture itself could be displayed as a tag <img> . But alas, you have to choose between <object> , <iframe> and <embed> . There is no significant difference between them, but the embed tag is excluded from the standards HTML 4.0 and XHTML 1.0, and the iframe tag is incompatible with Strict-specifications. Therefore, it is best to stay on the object variant as the most universal.
')
The object insertion code looks something like this:
<object data="./button.svg" type="image/svg+xml" style="width: 7em; height: 1.5em;"></object> 

Inside the tag, you can enter any HTML code: it will be used on browsers that do not support SVG. Well, it will come in handy for us, because sooner or later we would still have to remember about IE (and other browsers without SVG may occur). For them, we can add the usual <input type = "button"> inside the tag.

Modification of the text label

So we inserted our button. We are going to add a second one ... and immediately understand that for this we will have to create a new SVG file, since the label is stored inside the SVG code. But I would like to minimize the number of image files, because in particular, it was for this purpose that the use of the vector was intended! How to be? There are several possible ways.

1. Overlay the label over the button using HTML.
I’ll say right away that I haven’t investigated this method in detail, but with my gut I sense that it will bring a lot of problems. A typical solution to such problems is to position the text after the button and shift it to the left with CSS. But I am not sure that in this way it will be possible to achieve the correct centering of the text on the button. So - JS with positioning adjustment, means - constant tracking of the position of objects on the page (for example, when resizing windows or dynamically showing / hiding blocks) ... And also keep in mind that the button design may involve shifting this text down-right when processing (for the three-dimensional effect) ... In general, with only one thought about all this, I felt uneasy, so I began to look for other ways.

2. Insert text into SVG.
This option assumes that we have a script in the page code that runs through all the SVG buttons and inserts the necessary text into them (for example, by calling the function that was previously created for this in the SVG itself). This is better, but the unpleasant moment is that the button code and the text of this button are very spaced apart. You can, of course, enter after each <object> tag a short script line with the addition of the text of the button to an array, but still it is somehow long. There is a third way, in my opinion, more beautiful.

3. Pulling the text out of the tag.
The <object> tag has a standby attribute, which contains the text displayed by browsers instead of the contents of the object, while this object is loading. It turned out that the SVG-button may well get the value of this attribute and use it to modify the label on its own. And it turns out that in one fell swoop we kill two birds with one stone: on the one hand, we have a safety net in case of some sticking of the load - the user will see not an empty space, but a meaningful text (I, however, did not manage to provoke such behavior); on the other hand, the text label is now implemented as conveniently and clearly as the classic value in the <input> tag .

Click processing

The next problem is that we will not be able to hang a mouse click handler on the <object> tag : the click is sent to the SVG object and processed there. Naturally, we could push the event handling into the button, but this is unwise: there are a lot of buttons, and the SVG file is one. Instead, it is better to delegate processing to scripts from the parent page. Here, again, implementation options may vary, I stopped at the following: in the library JS file I defined the doClickAction function, which calls the handler of a particular button, and from the push-button script I call this function, passing it the button identifier. Sample code is as follows.

HTML page code:
 <object id="my-button1" data="./button.svg" standby="My Button1" type="image/svg+xml"> <input type="button" id="my-button1-ie" value="My Button1" onclick="javascript:doClickAction(parentNode.name);" /> </object> <object id="my-button2" data="./button.svg" standby="My Button2" type="image/svg+xml"> <input type="button" id="my-button2-ie" value="My Button2" onclick="javascript:doClickAction(parentNode.name);" /> </object> <script type="text/javascript"> // <![CDATA[ var signal_handlers = new Object(); function registerSvgAction(signal_id, handler) { signal_handlers[signal_id] = handler; } function doClickAction(signal_id) { if (signal_handlers[signal_id]) signal_handlers[signal_id](); else alert('Internal error: unknown SVG signal (' + signal_id + ')!<br />' + 'Please contact the developers.'); } registerSvgAction('my-button1', function () { alert('First button clicked!'); }); registerSvgAction('my-button2', function () { alert('Second button clicked!'); }); // ]]> </script> 

SVG Button Code:
 <svg version="1.1" onload="init()" onclick="doAction()"> <script type="text/ecmascript"> // <![CDATA[ function init() { // btnLabel  btnLabelShadow -  <text>     var btnLabel = document.getElementById('btnLabel'); var btnLabelShadow = document.getElementById('btnLabelShadow'); var newText = document.createTextNode(frameElement.standby); btnLabel.appendChild(newText); btnLabelShadow.appendChild(newText.cloneNode(true)); } function doAction() { parent.doClickAction(name); } // ]]> </script> 


In this code, I inserted additional <input> tags to display buttons in non-SVG browsers, and as a click handler, I assigned them to call the same doClickAction , passing it the identifier of the parent object 'a (i.e., the same that the handler will pass from SVG). Given this homogeneity, one could try to automate the insertion of these buttons by a script, but access to the contents of objects in IE is simply blocked. However, if you make a scripted passage, then it's easier to immediately replace all objects with buttons, without bothering with nesting.

Also here, one unobvious aspect must be taken into account: although the script actually calls the function of the parent page, the address of the SVG file will be considered the current address. As a result, all relative addresses will be counted from the directory where the button file is located, and not from the actual current page address. This moment will have to be taken into account, for example, when opening new windows through window.open () . The solution may be to use absolute addressing or to pre-save the current address in a variable and then use it to calculate the new address.

Font size

All this time I have carefully avoided the issue of font size for the text on the button. But now it's time to do this task. What would you like to receive? Ideally - the same font as on the main page. Unfortunately, we could not find a normal solution here. Apparently, it will be more correct in each specific case to estimate the extent to which the styles of the button label can vary, and depending on this, choose the least laborious way of implementation. For example, in my project the font is the same everywhere. Accordingly, I registered the font-family property directly in SVG, and I calculate the size in the initialization function, scaling the text according to the actual height of the button (which I get by referring to the element of the parent page). In more complex cases, it may be necessary to change the color of the lettering, the thickness or the type of the font itself. For such situations, you can use, for example, hanging the style on the <object> tag , then dragging it inside the SVG function init () , parsing and assigning the obtained styles to the text element. Alternatively, a global handler in the HTML code, which, after loading the page, runs through all the buttons, causing for each of them a “trimmer function”. I repeat, everything is too individual here, so that you can make some universal recommendations.

Unfortunately, even in such a simple solution, as my first option, there were some problems. Namely: if the button is initially hidden, then Firefox returns zero as its size, and the font size cannot be calculated. I could not come up with a correct solution to this problem, all the options look too ugly and / or inefficient. It was not possible to catch the button display event, because it simply does not exist. It is possible to make an explicit addition in the form of reinitializing a button when showing a previously hidden block, but there may be many such places and it is easy to forget about it. You can also try to somehow calculate the current font settings on the page and use the resulting size in the button.

Other problems

As you can see, there is no reason to talk about the simplicity of working with SVG. But, apparently, this was not enough, and after all the above-mentioned problems, new ones also got into the picture. They are difficult to break into some categories, so I just list all the things that I was "lucky" to run into.


Results

What remains in the bottom line? “Well, I didn’t hurt, I didn’t hurt!” I concluded for myself that the current infrastructure is not yet ready for the large-scale implementation of SVG (I apologize for the involuntary pun). To butt with all of the above (and, quite possibly, not only with them) problems, mistakes, deficiencies - all this takes too much time and effort, despite the fact that the limitations of current implementations do not even make it possible to take full advantage of the advantages that should would bring the use of SVG.

Well, a negative result is also a result. Perhaps sometime in the future, when SVG support improves, this experience will be useful to me for the final transition to scalable graphics. For now I will postpone it on a shelf until better times.

Hope the article was helpful. To some, it will help save time and nerves by discouraging the use of insufficiently developed solutions. And someone, perhaps, on the contrary, will move to further heroic efforts to overcome the desperate resistance of browsers.

We take leave and thank you for your attention.

UPD: Added to the list the problem of slow rendering in IE.
UPD2: In one place I confused the browser, fixed.

Source: https://habr.com/ru/post/111682/


All Articles