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:
- <object> tag ;
- <iframe> tag ;
- <embed> tag ;
- <img> tag ;
- 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:
- The <object> , <iframe> , <embed> tags are supported by all of the tested browsers.
- The <img> tag refused to work in FF, and in Chrome and Opera it works only in picture mode: embedded scripts and events are not processed.
- The background CSS style turned out to be the most versatile:
- in Firefox, it is not supported at all;
- Chrome is displayed correctly, but, as in <img> , event and script handling is not supported, and in addition to this, the animation does not work either;
- in the Opera it works, it does not; it seems that the style does not work if the <img> tag with the same SVG image is also present in the page code, and this tag should be located before the element with the image background. In all other cases, the background works correctly, but, as in Chrome, it is displayed with a static picture, without processing events, scripts and animations. (By the way, thanks to Xpeh and tenshi for their clarification about this functionality in the comments to the previous article.)
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.
- Opera: The dominant-baseline text style does not work to change the position of the font base. As a result, it becomes impossible to align the text vertically, you have to adjust the position, or even adjust it dynamically depending on the size of the button and the font, so that the text label looks decent.
- Chrome: When using page scaling, SVG elements are scaled, but the sizes of the areas allocated to them are not. As a result, the buttons crawl out of the regions and are cut off, and scroll bars appear, closing most of the image. The main advantage of SVG - scalability - is simply thrown into the garbage!
- Opera: Actively buggy when reusing images from the cache. In particular, if you click on the link, and then click the Back button in Opera to return to the previous page, all SVG images are not displayed, and “hang” in the internal SVG initialization script. Also, sometimes there are problems with the dynamic creation of the SVG button through createElement : if an image present on the page is used, it hangs up the page loading and is not displayed until you press Esc (and even after that all sorts of unpleasant effects are periodically observed).
- General problem: The font size in the above solution is fixed and does not change when the page is scaled, the size of the button and the caption cease to match each other. Accordingly, after changing the scale, the page needs to be reloaded so that the buttons re-initialize with the correct font size. I do not exclude that I did not understand this with the units of measurement, but I did not succeed in solving this problem. Perhaps the tweak can be implemented with some kind of global JavaScript handler that somehow monitors the scale and causes a forced update of the buttons.
- Firefox: In the “Text Only” scaling mode, something terrible happens with the font size. I could not immediately understand the rules for the size of elements in this mode, and I did not see the point of lingering on this problem.
- IE: As it was said, SVG is not supported in it, and instead of pictures, the usual buttons that I put inside the <object> tags are displayed. The problem is that IE is very tight that he does not know how to work with SVG. Therefore, having met the button, he displays an empty block, thinks for a while, then draws a button instead of a block. Then the same with the second button, with the third ... In general, the drawing of six buttons takes a second and a half to two in it.
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.