How to react on style changes within a Web page? - javascript

Lets assume that we have a responsively-designed Web page which uses media queries to achieve three different views: screen, handheld and print. Lets assume further, that such a Web page includes several JS-based, view-dependent layout fixes, navigation logic, content-generating macros and similar stuff, reason for which may be more or less controversial.
Now, please imagine that users are playing with our design by resizing browser window and printing it's contents. A we would like to react on the style changes (carried out by the browser) in order to recalculate layout fixes, regenerate dynamic content, rearrange navigation or whatever else. But there is no "onMediaChange" event to be handled by our script, is it? So, in what way could a Web developer synchronise the media-driven style with the media-independent logic?
This question, in several forms and development contexts, has been asked on StackOverlow for years, but no rewarding answer has been given yet. There are workaroundss using width-based conditionals, but these neither handle the print view, nor react to width changes occurring after the page has loaded. Other group of CSS-sniffing solutions is based on polling which is fallible and inelegant. What I am looking for is a general, elegant, standards-compliant, client-side solution for synchronising JS and CSS with media changes. Two non-existing, ideal solutions could be:
The existence of an onMediaChange event, e.g.:
document.addEventListener('onMediaChange', myHandler, false);
The possibility to attach scripts with the link tag, e.g.:
<link rel="script" media="print" type="text/javascript" href="print.js"/>
I'll be grateful for any existing solutions, creative suggestions, theoretical comments or even a philosophical discussion exceeding the scope of this question.

I think you're looking for window.matchMedia API:
https://developer.mozilla.org/en-US/docs/DOM/window.matchMedia
Basically, it'll let you attach an Event Listener to media queries. You could pair this with an append() method to add/remove dinamically <link> tags.
Unfortunately, as far as I know, it is poorly supported among old browsers, but using a polyfill (like this one) you could potentially get a global, cross-browser support.

Related

Should I inject style tags into the head dynamically or include include style tags in the body?

I have some html content that gets embedded into a page via a server side call. So, when the page's html is being compiled on the server, a call is made to another server to return some html, which is then embedded within a div somewhere in the body. The problem is, this content contains it's own css. So, I wrote a script to inject style tags into the HEAD on ready, which works fine on desktop browsers. However, on mobile devices there's a fairly significant flash of unstyled content. I know that you're technically not supposed to include style tags in the body, but in this case would it yield better results to just include them in the body instead of injecting them into the head?
In this case, it sounds like the right solution is to fix up your architecture so that the server-side compiler can include CSS for the remote page in the page head. This probably involves separating the CSS of the remote page(s) out of the markup there and then grabbing it as a separate file to be included in the page head during compilation.
Since the right solution is not always feasible given a myriad reasons, compromise is often required. Leaving the CSS in the remote markup, if it produces the result you desire, could be the best solution for you. Or perhaps some other hack to get the CSS into the head server-side could be appropriate. You need to decide if it is worth the effort to do any of these things, if they are possible for you to accomplish given your constraints.
Some discussion here. In my experience a lot of enterprise content does it. Does that mean it's the RIGHT thing to do? I dont know. But it's certainly not frowned upon in my experience.
Source: https://www.w3.org/wiki/The_web_standards_model_-_HTML_CSS_and_JavaScript
Why separate?
Efficiency of code: The larger your files are, the longer they will take to download, and the more they will cost some people to view (some people still pay for downloads by the megabyte.) You therefore don’t want to waste your bandwidth on large pages cluttered up with styling and layout information in every HTML file. A much better alternative is to make the HTML files stripped down and neat, and include the styling and layout information just once in a separate CSS file. To see an actual case of this in action, check out the A List Apart Slashdot rewrite article where the author took a very popular web site and re-wrote it in XHTML/CSS.
Ease of maintenance: Following on from the last point, if your styling and layout information is only specified in one place, it means you only have to make updates in one place if you want to change your site’s appearance. Would you prefer to update this information on every page of your site? I didn’t think so.
Accessibility: Web users who are visually impaired can use a piece of software known as a “screen reader” to access the information through sound rather than sight — it literally reads the page out to them, and it can do a much better job of helping people to find their way around your web page if it has a proper semantic structure, such as headings and paragraphs. In addition keyboard controls on web pages (important for those with mobility impairments that can't use a mouse) work much better if they are built using best practices. As a final example, screen readers can’t access text locked away in images, and find some uses of JavaScript confusing. Make sure that your critical content is available to everyone.
Device compatibility: Because your HTML/XHTML page is just plain markup, with no style information, it can be reformatted for different devices with vastly differing attributes (eg screen size) by simply applying an alternative style sheet — you can do this in a few different ways (look at the [mobile articles on dev.opera.com] for resources on this). CSS also natively allows you to specify different style sheets for different presentation methods/media types (eg viewing on the screen, printing out, viewing on a mobile device.)
Web crawlers/search engines: Chances are you will want your pages to be easy to find by searching on Google, or other search engines. A search engine uses a “crawler”, which is a specialized piece of software, to read through your pages. If that crawler has trouble finding the content of your pages, or mis-interprets what’s important because you haven’t defined headings as headings and so on, then your rankings in relevant search results will probably suffer.
It’s just good practice: This is a bit of a “because I said so” reason, but talk to any professional standards-aware web developer or designer, and they’ll tell you that separating content, style, and behaviour is the best way to develop a web application.
Additional stackoverflow articles:
Using <style> tags in the <body> with other HTML
Will it be a wrong idea to have <style> in <body>?

Multiple jQuery scripts used - how include these in an extendable OO way?

Are there any docs or training materials available that advise the best way to include multiple jQuery plugins in an abstract way, allowing for extension of those plugins, and also global control of things like events, setTimeout() etc?
I want to be able to do these kind of things:
Extend someone else's jQuery plugin, e.g. if I want to add a new feature, but not touch the original codebase
Have my own server-side detection script pass a value to JS (using a HTML meta tag) so JS can detect that and then decide which script to use (e.g. tone down some of the jQuery for lesser devices)
Better control all the events that are attached
setTimeout() - I have loads of these dotted around the place at various intervals - I want to control all this in one function
Add my own fixes to jQuery scripts. If I download a ready-made one and use it I always find I can improve usability - especially on mobile devices - so I want to add my own fixes and improvements.
Control the resize event. There's all sorts going on at the moment and it's quite a job triggering a full re-size when I write new code (and the resize is pretty slow on some mobile devices)
You can use RequireJS or similar library to load scripts dynamically depending on screen size or navigator's user agent parameter (You will need to set condition checking yourself though).

Best practice - pre-write HTML in document with display:none, or create with JS?

I am developing a large scale HTML5 app, and I really wonder about this issue. I will have a lot of dialog boxes and tabs that will open by user interaction.
I wonder what is the best practice - writing all the dialog boxes and tabs in the HTML document with display:none to all of them, or create these HTML sections on the fly with JS or jQuery every time the user making the relevant interaction.
What is better in terms of performance, ease of development, readability, etc?
Any help will be appreciated.
I'll try to address this question as good as I can.
1 - As I said in the comments, Avoid inline styling.
First and foremost this is because inline styling voilates DRY.
Having to repeat the same thing over and over again for this is very bad for maintenance and for developing since instead of changing code once you have to change it at ~100 places.
2 - Avoiding inline styling is also good for accessibility, some screen readers and search engine crawlers do indexing work and reading work based on css selectors and thusly using inline styling will force them to either ignore or misintrepret things.
3 - When working as developers it's easy to do inline styling "just for the fun" but what you're actually doing is mixing concerns. HTML is the content and CSS is the design.
Mixing these two usually leads to headaches and making my job as a developer that comes after you a pain in the effin ass since I have no idea what's styled and how.
Now, onto performance.
When you use inline styles, what you're telling the browser is basically "hey, for every page page view apply these styles to all of these elements." Now, this just became really apparent why this is bad.
You have no ability to cache and store your css and basically forces the browser to rerender your styles every time. Using an external CSS file will actually help you speed up your site since the browser caches it.
That was that for the css part.
The javascript you had asked about.
As I said, hide things with css and show with javascript. Now why do you want to do this instead of pulling everything in?
Well, you can do both. If you're only a webbrowser experience then you can do either, it doesn't matter. I myself prefer to have stuff in the DOM because it relates to content and if you're a large app having dozens of dozens of ajax calls will only make it harder for maintenance. I believe if you have to ajax stuff in make sure it counts and is logical and not just for the kicks (I think this applies if only you have jQuery and plain javascript at your disposal).
If you're working with backbone.js, for example, it's based on views and introduces some form of "MVC" into your frontend enabling you to have views with subviews that can pull content in from the server.
Hope that helps a bit with making a decision! :)
I would say it depends on how many tabs your application has and how big these are.
Big content inside the tabs mean that the application will take long to load when started and consume much ram. If this is the case, I suppose to load them as needed.
Small content inside the tabs will load fast, so load everything at once to increase performance when the tabs are clicked.
Don't forget to run some tests on older computers with a slow internet connection to see how your application behaves. Not everyone has the newest and fastest hardware.

Javascript widget implementation

I have a question about Javascript widgets. The widget I am working on simply embeds content on a page instead of using iframes. So far it looks good. But there are cases where some users layouts are messing up the widget. For example, the widget might require a width of 300px to appear. But the parent div is set to 250px and hence the right part of the widget is cut off.
I was wondering what sort of precautions should be taken to prevent this? I was talking to the product manager who mentioned he wanted me to check the parent div elements and get the size and then show an alternate message if their size is not accurate. But again, since this is Javascript and the widget is supported in many diff browsers(including IE6), I am wondering how fail-safe this method would be? What if I need to iterate the DOM all the way up before getting a valid size? I am also worried about performance here. This extra checks would slow down the delivery of my widget content to "good users" since I am adding a layer of complexity to all users. I don't want to penalize good users just because of the few errant ones.
I am not using any sort of JS library here, so any solution should not suggest the use of one. Also, the reason for not using a library was simply not to add extra weight to the page load to deliver a widget. I understand that "jquery" for example is small, but in my case, even 24k compressed seems like an overkill for a widget delivery that contains no core code for the widget.
Has anyone dealt with such issues before? What are your solutions to these?
There are reliable ways of determining the size of an element using JavaScript. You're quite right that you may need to iterate up the tree in some cases, but the answer you get will ultimately be quite valid.
Although you don't want to directly include any library code in this project, you may consider looking at how the major libraries implement their "what's the width of this element" functions to drive your own implementation.
Beware of quirks mode too.
I'd check to see of the page has Jquery, if not load it into the page using no-conflict mode. Then use jQuery to examine the page.
See: How to embed Javascript widget that depends on jQuery into an unknown environment

What's the most efficient way to hide content for a mobile version of a site?

I'm working on a mobile version of a large site. There's a lot of content from the full site that's not needed for mobile.
What is the best way to hide this?
i.e. What will cause the least amount of work for the browser, so it stays responsive?
CSS display:none
jQuery's .remove() method, for example (not tested):
var elements_to_remove = [
'#sidebar',
'#footer',
'#etc'
];
$.each(elements_to_remove, function() {
if ($(this).length > 0) {
$(this).remove();
}
});
The advantage I can see for .remove() is that the elements are actually removed from the DOM tree, reducing memory usage.
For the jQuery route, is there a better event to hook on to before document.ready? (i.e. while the DOM tree is being made).
Also, any recommendations for how to benchmark this?
Update: Providing a custom mobile version is not an option, it should work with the existing content / be 'responsive'.
The most efficient way will be to not include the content on the page in the first place.
Mobile users will thank you for not wasting their data tariff with elements that are not shown on the page and will be happy if they don't need JavaScript in order to view the page correctly.
Both HTML and CSS provide ways of doing this without JavaScript.
As per the above link, you can specify different stylesheets for different devices using:
<link rel="stylesheet" href="screen.css" media="screen"/>
<link rel="stylesheet" href="handheld.css" media="handheld"/>
Or if you want to use a single stylesheet:
#media screen { /* rules for computer screens */ }
#media handheld { /* rules for handheld devices */ }
or with #import:
#import "screen.css" screen; #import "handheld.css" handheld;
A mobile portal is probably the best option since mobile users likely have different surfing patterns and different uses (are looking for different info, using different features, etc.) for the site. But if you want to maintain a single portal, then just make use of what is already provided in the HTML and CSS specifications.
Note:
If you're adhering to the MVC design pattern, then it should be relatively easy to build a single application and render different Views to the user depending on whether they access the site via http://myapp.com or http://mobile.myapp.com. This means your Controllers and Models stay the same, and you just need to create separate views for the parts of the app that mobile users will access. The same technique would be used for generating RSS feeds or implementing a REST API.
Edit:
The issue of newer non-compliant mobile browsers is a bit tricky. On the one hand, the reason they render both spreadsheets is because they felt that web devs were dumbing/stripping down their sites too much for mobile users (for good reason, as many older, less advanced mobile browsers are still used), and mobile browsers are catching up to desktop browsers in rendering capabilities. But OTOH, the resolution difference and screen size is still an issue.
So what I would do is use 2 sets of spreadsheets, but design for 3 sets of users:
desktop users: loads screen.css only
new mobile users: loads screen.css and handheld.css
old mobile users: loads handheld.css only
The cascading nature of CSS means that, with some careful testing, you should be able to cater to all 3 demographics. There may be some browser-detection tricks that you could apply, but that doesn't seem necessary.
If you are developing for mobile, your first priority is to reduce bandwidth. The responsiveness of the site on mobile is usually less dependent on how fast it is rendered, but by how fast it is loaded (without even mentioning that users often pay for traffic).
On a related note - keep in mind the smaller screens on mobiles. It often makes sense to make a lighter site (both in bells in whistles and in content per page).
Given the case where the content for mobile is much smaller than the original version, it is a good idea to not share code as much as possible. Put your code in a seperate folder for the mobile app. You don't state how small is small, but it may be worth your while to do this even if it means a smalll amount of duplication.
Sometimes it is better to be pragmatic rather than follow to the letter a set of rules, such as DRY.
A very fast way to add or remove HTML is to use innerHTML, something like:
node.innerHTML = '';
node.parentNode.removeChild(node);
And you can place these commands in a SCRIPT tag at the end of the BODY tag.

Categories