📜 ⬆️ ⬇️

Dinosaur Walking: How I Adapted a Web Application for IE 7

image

Recently, I decided to send my project, on which I had worked in my spare time over the past few years, to a competition in one company. I sat down and began to think if there were any nuances that I did not take into account and which could spoil the impression and reduce the chances of success. And the first thing that occurred to me was that the project did not work under IE below version 9. That is all, there was a lock. After login, a window appeared with a beautiful warning that the browser is not supported, and the user was again thrown onto the login form. Quite elegant - but unpleasant. What if a person has Windows XP, and no third-party browsers? Bad luck

And so I decided to spend as much time as I need, but at the same time achieve a stable, error-free system at least in IE 8. I was ready to remove some of the functions, if necessary, but everything had to look neat and work without failures. Anticipating long and heavy torment (I already had a similar experience several times), I got down to business. If you are interested to know what difficulties I encountered, and what changes I had to make to different components, welcome to Cat.

I began to remember why I did it - and remembered that I didn’t even try to correct the flaws in the layout after I saw that the data did not come through the XHR. Judging that an instant messenger without auto-update, where you have to press F5 all the time is a complete circus, I introduced that lock.
')
However, after this there were already 2-3 cases when I came across similar symptoms and successfully eliminated them. And somehow I forgot about this project that the problem was the same here. This first correction fixed the most important problem, which, in turn, opened the way for further improvements.

Below I will list the main incompatibilities that may have to be considered if you decide to provide support for older versions of Internet Explorer. So let's go!

IE doesn't know what CP1251 encoding is (all versions)


This problem - paradox - is still present. All versions of IE are affected by it, up to the 11th. Perhaps, Microsoft does not consider this a bug, but during development this has to be taken into account - otherwise the browser will ignore all data that came through AJAX. There are two solutions here: either add the encoding via .htaccess (if you have Apache), or add it via header() directly in the PHP code. The second option is more universal (should work with any web server), but more laborious, and obviously clogs the code, so I prefer the following line in the config file:

 AddDefaultCharset windows-1251 

After this, the response header is Content-Type: text/html; charset=CP1251 Content-Type: text/html; charset=CP1251 changes to Content-Type: text/html; charset=windows-1251 Content-Type: text/html; charset=windows-1251 , and it will work.

Lack of support for some pseudo-classes (IE8 and below)


For example, the nth-child() selector does not work. What creates big problems when the layout and styles are already written. Again, there are only two adequate solutions - either prescribe the necessary blocks (for example, the second in the container) a special class in all places in HTML, or write a single JavaScript function, and assign the necessary styles in it through the style. The second option seemed more advantageous to me, since the markup is not clogged with unnecessary classes, less work, easier to remove in case of anything - and most importantly, in this case, you can run this code only for IE of the necessary versions, turning it into if() . Please note: if you choose the first option, you cannot do with conditional comments, you will have to change the markup itself, adding an extra class attribute where it is not needed in general.

Lack of background-size support (IE8 and below)


Yes, the background-size property is part of CSS3, so there is no support for it. Predictable, but very sad. Imagine, for example, that we have a small icon, which is almost the right size, but not quite (for example, it is more than 20-50 percent). When developing, we could make an ordinary div, assign it as a background and set the background-size. In IE8, we get it in full, larger size. Here you can change the layout, making img, and giving him the size. But it’s usually cheaper to make one (or as many as necessary) copies of a picture of the right size, and leave the markup as it is.

No display: inline-block (IE7 and below)


It should be replaced with display: inline , it works in exactly the same way (external indents are supported, and this is usually enough). In especially difficult cases, you can try float: left (or float: right , if you need alignment along the right edge, though in this case the order of the elements will change to the opposite, and you will have to add more JS code).

List bug (IE7 and below)


I often use a list for a non-intended purpose: for example, to create a series of horizontal links, or drop-down menu items. But this time I had to change the markup, because I could not find solutions for this problem. IE7 (and IE8 in emulation mode) adds an indent to the left of all items. At the same time, the container padding is zero, the margin on the <li> elements is also, and a fixed distance of 26 pixels is listed in the inspector as offset (to the left of the margin ). At the same time through CSS it can not be removed in any way (or I did not find how to do it).

UPD: andy128k prompted a solution to the problem: it is necessary to specify list-style-position: outside for the list items, and the indent disappears.

Difficulties with mixing own functions into prototype (IE8 and below)


In browsers like Chrome, Opera and Firefox, you can add the necessary properties to the prototype of the elements through the HTMLElement object. In IE 8, when you try to do this, you get an exception, even if you just write an if with this name — so you must use the try {} block. But the Element object performs the same function there. But in IE7 you can not do this. You can of course add properties to the Object.prototype - but this is not very good practice, in my opinion. Therefore, if IE7 support is necessarily needed, and there are not very many mixed functions, it is easier to abandon the syntax with a dot at all. And write something like addClass(obj, className) instead of obj.addClass(className) .

Absence of nextElementSibling and previousElementSibling (IE7 and below)


Yes, yes, these properties also do not. Totally. There is of course a collection of children, which you can travel, but in a number of places where you need to get the next element, you have to use stupid while() loops on one line, going through nextSibling / previousSibling, until we find an element of the desired class, or with nodeType equal to one . Here it should be noted that in IE, the corresponding versions of nextSibling and previousSibling just skip text nodes. Only in other browsers this is not the case, and cross-browser compatibility will disappear immediately (the code will stop working everywhere except IE), if you make a simple replacement.

Missing JSON object (IE7 and below)


Everything is simple - we write our parser / encoder (good, it's not so difficult). You can also use eval , especially if the data source is trusted, for example, our server. But knowledgeable people do not recommend doing it anyway :)

Unexpected rake with HTTPS (IE7 and below)


In my project, data is obtained from a third-party resource via the API via the HTTPS protocol. You can imagine my surprise when on a real IE7 on a virtual machine I didn’t get that data via JSONP, which I perfectly received in IE8 in IE7 emulation mode. I don’t know what was the matter, but it looks like something with a set of supported ciphers - the server simply does not allow to establish a connection. Check it was easy - just opened the desired address in a new tab and saw the SSL error. And the same mistake was when opening any page of that site. What's interesting - the encryption protocols in the settings for IE7 and IE8 are the same: SSL 2.0 (not checked), SSL 3.0 and TLS 1.0. And the key length in the window "About" and there and there is equal to 128 bits. But for some reason, IE7 server otshivaet. If anyone knows the reason for this phenomenon - write in the comments.

Other device selection


If we need to somehow work with the selection - it does not matter, the selection is just on a web page, in input or textarea - for IE you need a separate code. Not that it was much more difficult in the general case — however, in simple situations (such as “inserting text at the cursor position into the text field”), the approach is really less obvious and requires deeper knowledge.

There are a lot of code variants for cross-browser framing a piece of text with a tag, or inserting text into an arbitrary position (which is essentially very similar) on the Internet. My version, which I once copied from somewhere and did not really test it (since I am working on the Opera), did not work. The correct version was found the other day in a well-known forum, its authorship is collective. In general, I have nothing to do with him, but I will give it here in a very abbreviated and simplified form (so that the idea was clear, and there was not too much):

  if (detectIE() < 9) { window.sel = null var f = function() { window.sel = document.selection.createRange().duplicate() } document.getElementById('inputField').onselect = f document.getElementById('inputField').onkeyup = f document.getElementById('inputField').onclick = f } function tagSelectedText(obj, tag) { if (document.selection) { if (!window.sel) return document.getElementById('inputField').focus() var sel = window.sel var len = sel.text.length sel.text = '<' + tag + '>' + sel.text + '</' + tag + '>'; if (len == 0) sel.moveEnd('character', -(tag.length+3)); sel.select(); } // ...    } 

The idea is that there is an invisible object of selection (and often not in the singular, it is sometimes incidentally seen in Opera, if you select something with the mouse, before this, in JS, without having to programmatically reset everything in the Range). But he disappears as soon as the field loses focus. And on onblur assign the function of its duplication is useless: it's too late. Therefore onselect. onkeyup and onclick are needed in order to preserve an empty selection (zero length) as you type or move the cursor across the field with arrows or mouse clicks.

At the moment of pressing the button, we take the saved object, update the text property of the real selection object, using the property of the saved object. If necessary, move the cursor. Do not forget to call select() - it is important to do so that the result is displayed in the browser.

Brakes sometimes detect errors in logic


In one place in the JavaScript code (in the place where the audio player interface is created) a request was made to an external server via JSONP. The handler function received the desired player (the one that was used in the createPlayer() function at the time of creating the request) by its id, which was calculated based on the response to the request, and assigned an attribute with the track URL, calculated from the same answer. Everywhere, including IE8, everything worked well and as planned. And in IE7, the function called via JSONP could not get the player's container object by id.

It turned out that the problem was that at the time of the getElementByID() call, the message container in which the player's desired container was located was not yet added to the right place by the appendChild() method that was after calling createMessage() , which creates the message. But already existed, and id had the right one. In fact, elements created through createElement() do not become available instantly. This is normal. And of course, you should add an element to the DOM, and then access it. But usually I first assign all handlers and fill the element with child nodes, and only then add it. Therefore, here the evil joke was that the function handler code worked at an unknown point in time, and in IE7 the execution of the main thread was not completed by that moment (or the DOM was not updated).

Features of working with DOM also reveal errors in logic


Here everything was more interesting to some extent. The xPlayer library has the ability to connect and remove "listeners" (when it was developed at the time, it was specifically done in case it was needed, and that's what was needed). This feature was used to connect controllers (those players that appear in messages) to the master player at the top of the page. The master player allows you to scroll the conversation and even switch between rooms, all the while having access to control playback. When returning to the room where the track was launched (or loading the message block where it was launched), the required controller “grabs” when it is initialized. The controller's initialization code compares the special uid formed from the URL and the track name with the master's uid, and by their coincidence, and concludes that this controller is “the same”. At the same time, all controllers, without exception, when creating, have a set of functions that update their UI during various events. And these functions are registered as “listeners” in the master.

An unexpected error was revealed in IE8 - after switching to another room, the listener function continues to execute and crashes when trying to determine the clientWidth element that is removed from the document after cleaning the innerHTML viewport!

On the one hand, the reference to the element was passed as the context when registering the function, and the garbage collector should not destroy the object, even though it is no longer part of the DOM. But this is in other browsers - it looks like the object was just being destroyed, and the clientWidth property was clientWidth taken from the null pointer. Other browsers did not issue any errors to the console (most likely clientWidth there was 0, and the object existed with all its descendants outside the DOM), and when returning to the old room everything worked fine.

Here, when the controller returned, the scale of the controller was not “picked up”, and the scale of the master player continued to be updated all the time (the update function is assigned when starting playback via setInterval() , all the functions from the list are started from it).

Obviously, the update function itself worked, but the listener function did not. Well, the problem most likely was that the new listener function was added to the list upon returning to the previous room (with reference to the new object), but it didn’t have time to go to it, because when the old one that was in front of it started, the code fell from by mistake. And the mistake is utterly banal - when changing a room, the list of functions-listeners should be cleared :)

By the way, this is the problem and solved.

Safety first (IE8 and below)


Probably, everyone who has worked more or less with the development of interfaces, knows a simple technique how to style input file type. It is enough to make it hidden, and by clicking on an arbitrary element that will play the role of a button, hang up a handler function, within which to make a call

 input.click() 

But in IE8 and lower versions, if you try to submit a form with a file selected in this way (for example, through a call to form.submit() hung on the onchange on the onchange ), we get an error:

image

Microsoft believes that this is an unsafe operation, so it gives us a hands-on. Therefore, to stylize the file in the usual way in Internet Explorer will not work. By the way, even if you make it visible through JS before submitting the form, nothing will change. It is necessary that the file was chosen by direct click on the input. Therefore, the only way is to make the input transparent using filter: alpha(opacity=0) , and put a stylized button under it. Then the user will click on the real (transparent) input.

What about IE6?


With IE6, everything is bad.

image

I never really worked with this browser as a developer - it was not possible due to age. But I read somewhere briefly that there was another block model in general, and in general a bunch of crutches were needed. So far, in IE6 everything looks the same as in IE7 with an unspecified DOCTYPE (so-called quirks mode), or as in IE8 in the emulation mode “IE7: compatibility mode”.

But if someone has ideas that need to be added in the styles, so that the situation at least slightly corrected - I will be grateful.



In addition, we should not forget that work with events everywhere was organized crossbrowser (otherwise the code will fall, and nothing good will happen), that the rounded corners of the elements, where it is vital, were made with pictures (or at least have pictures as an alternative fallback). In addition, objects that have the effect of smooth appearance and fading through transparency will not have font smoothing (though this bug can be circumvented by assigning a filter before setting the display to the block , and removing it altogether after the effect is completed).

Well, even after all this, a serious web application will work rather slowly (even the usual custom scrolling slows down, and with not very large amounts of content). But at least with all these conditions, the resulting result can be called graceful degradation. Probably.

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


All Articles