Solved

Using JQuery with responsive design

Posted on 2013-11-20
17
538 Views
Last Modified: 2013-12-04
Hi,
I am building a respsonsive site and the more I seem build it up the more complex and unstable my JQuery is becoming.
I have one media query in my CSS to determine between my two states of desktop and mobile (mobile < 640px width)

One example of the issues I have is with some hide/show elements on the page.

I have a filter menu (not the navigation) that is always to be shown in desktop but needs to be collapsed in mobile. Therefore I have the CSS styles to make this happen, however when in mobile and the display filters button is clicked it needs to then show it - the jquery then creates an
inline style for the element overwriting any CSS styles set to it, therefore when the user then changes to desktop by making the viewport wider it is still in the state that the jquery last set it as (so if they hid it in mobile, it will still be hidden in desktop).

To overcome this I have added in a function that checks everytime the viewport width is changed via $(window).resize(function_name); so that if the window is in the desktop range it will automatically show(); the filter menu and vice versa for mobile.
This is fine, however it is moving me away from controlling the responsive design in the CSS and as I introduce more and more of these elements it becomes increasingly difficult to manage and is causing some issues.

One being, if the user changes from portrait to landscape in mobile it reads this as a viewport width change and therefore hides the filter menu even though they might have it open and be browsing it.

My more complex issues are with trying to unbind and bind 'onclick' functions etc depending on the viewport width too.

Do you have any suggestions as to how to approach this better or ways to tidy it up?

Example structure of my js:
var responsive = function () {
    $(document).ready(function () {
&#9;&#9;var pageType = $("#pageType");
        //Pages
        if (typeof pageType === 'object') {


            if (pageType.val() == "tour-results-page") {
                //trigger viewport resize check
                $(window).resize(tourResultScript);
                tourResultScript();
&#9;&#9;&#9;}
&#9;&#9;&#9;if (pageType.val() == "tour-details-page") {
                $(window).resize(tourDetailScript);
                tourDetailScript();
&#9;&#9;&#9;}
&#9;&#9;}
&#9;&#9;
&#9;&#9;function tourResultScript() {
            var windowsize = $(window).width();
&#9;&#9;&#9;
&#9;&#9;&#9;if (windowsize < 630) {
&#9;&#9;&#9;&#9;responsive.toggleContent.filter('.filter-open', '.filter-form', '.filter-open .arrow', '#sort-options', '.tour-sort .arrow');
&#9;&#9;&#9;} else {
&#9;&#9;&#9;&#9;responsive.toggleContent.unbindElement('.filter-open');
&#9;&#9;&#9;}
&#9;&#9;}
&#9;&#9;responsive.toggleContent = {
&#9;&#9;&#9;filter : function (activator, toggle, arrow, hide, other) {
&#9;&#9;&#9;&#9;$(activator).unbind('click').bind('click', function(e) {
&#9;&#9;&#9;&#9;&#9;$(hide).hide();
&#9;&#9;&#9;&#9;&#9;$(toggle).slideToggle(500, function(){
&#9;&#9;&#9;&#9;&#9;&#9;if($(this).is(':visible')){
&#9;&#9;&#9;&#9;&#9;&#9;&#9;
&#9;&#9;&#9;&#9;&#9;&#9;&#9;if ($(this).attr('id') == 'sort-options') {
&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;$(arrow).css("background-image", "url(img/mobile-less-arrow.png)");
&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;$(other).css("background-image", "url(img/mobile-more-arrow-white.png)");
&#9;&#9;&#9;&#9;&#9;&#9;&#9;} else {
&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;$(arrow).css("background-image", "url(img/mobile-less-arrow-white.png)");
&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;$(other).css("background-image", "url(img/mobile-more-arrow.png)");
&#9;&#9;&#9;&#9;&#9;&#9;&#9;}
&#9;&#9;&#9;&#9;&#9;&#9;} else {
&#9;&#9;&#9;&#9;&#9;&#9;&#9;if ($(this).attr('id') == 'sort-options') {
&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;$(arrow).css("background-image", "url(img/mobile-more-arrow.png)");
&#9;&#9;&#9;&#9;&#9;&#9;&#9;} else {
&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;$(arrow).css("background-image", "url(img/mobile-more-arrow-white.png)");
&#9;&#9;&#9;&#9;&#9;&#9;&#9;}
&#9;&#9;&#9;&#9;&#9;&#9;}
&#9;&#9;&#9;&#9;&#9;});
&#9;&#9;&#9;&#9;&#9;return false;
&#9;&#9;&#9;&#9;});
&#9;&#9;&#9;}
&#9;&#9;}
&#9;});
}

Open in new window


Thanks
0
Comment
Question by:Al4ddin2
  • 7
  • 4
  • 2
  • +1
17 Comments
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
Comment Utility
I would suggest starting from scratch, but use a library  like bootstrap http://getbootstrap.com/  I have more details on this here

http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/HTML/Q_28293862.html#a39648026

http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/Q_28292934.html#a39644671

Below is sample code from bootstrap's grid that takes care of going from columns to stacked with mobile.  They have the media queries built in so you can just use classes.  It is much easier.  And yes, responsive does take a lot more thought for each page you layout.
<div class="row">
  <div class="col-xs-12 col-md-8">.col-xs-12 .col-md-8</div>
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
</div>

<!-- Columns start at 50% wide on mobile and bump up to 33.3% wide on desktop -->
<div class="row">
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
</div>

<!-- Columns are always 50% wide, on mobile and desktop -->
<div class="row">
  <div class="col-xs-6">.col-xs-6</div>
  <div class="col-xs-6">.col-xs-6</div>
</div>

Open in new window

0
 

Author Comment

by:Al4ddin2
Comment Utility
Hi,

Thanks but its not the responsive layout side of it that i am struggling with.
I have based my website build on bootstrap and am using their grid system fine - the page looks great in both mobile and desktop - its more to do with handling the jquery side of it I am struggling with.

Thanks
0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
Comment Utility
If you check out the bottom of the page http://getbootstrap.com/css/ you will see the table on how to make items visible or not based on the viewport.  Did you try that?

This is a sample http://jsbin.com/IKAbajOn/1/edit?html,output

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery.min.js"></script>
<link href="http://getbootstrap.com/dist/css/bootstrap.css" rel="stylesheet" type="text/css" />
<script src="http://getbootstrap.com/dist/js/bootstrap.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <div class="visible-xs">XS</div>
  <div class="visible-sm">SM</div>
  <div class="visible-md">MD</div>
  <div class="visible-lg">LG</div>
  
</body>
</html>

Open in new window

0
 

Author Comment

by:Al4ddin2
Comment Utility
Sorry padas, I dont think you are understanding my issue.
I have things hiding and showing for mobile and desktop correctly.

I am using media queries and the bootstrap framework to help me and it is working fine.

The issue I am having, as stated in the initial request, is when I apply say a jquery onclick to a div class that has content collapsed for mobile (but shown in desktop) the CSS successfully collapses the div but when the user clicks on the div and the content then
displays, whilst in mobile, (toggle) the jquery will append an inline style of display:block to the element as it should, if the user was to click it again to collapse it (display: none) if they were then to change to a viewport of greater than 640px the div would still be
hidden as the inline style set by the jquery onclick would over-ride the CSS.

Does this make sense?
0
 

Author Comment

by:Al4ddin2
Comment Utility
Can anyone assist? - Would you like me to post more of my JS?
Thanks
0
 

Author Comment

by:Al4ddin2
Comment Utility
What is the industry standard for dealing with differences in jquery functions and toggling binding/unbinding them when building responsive sites?
Is there a better way then checking and firing the scripts as and when the viewport changes size?

Any advice would be very much appreciated.

Thanks
0
 
LVL 53

Expert Comment

by:COBOLdinosaur
Comment Utility
You have made the biggest possible mistake you can make; allowing jquery to write inline styling.  That destroys the integrity of the CSS and breaks the the document object.

If you cannot handle all the effects you need with media queries (there is much more to them then just looking at screen size, then you need to define classes for the various states for elements, and limit the use of jquery presentation operations to changing the classes of elements.  

Under no circumstance should you use inline styles.  If you do that you will just end up adding hack on top of hack on top of hack until the whole thing collapses into a pile of rubble.

you might want to take a look at all the options available in media queries from a professional source here.

Cd&
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 42

Accepted Solution

by:
David S. earned 500 total points
Comment Utility
Al4ddin2, I'm not aware of any industry standard for dealing with this. Responsive web design has not been widely used for very long. Keeping paths to background-images that are just static strings in a script seems like a bad idea. Besides the conflict you mentioned, such a practice violates the principle of "separation of concerns".  It's much better to move those to your stylesheet, each with a different class.

Cd&, even if he wasn't using inline styles directly, several jQuery methods including hide, slideUp, and slideDown use inline styles to work. Callback functions can be used with such jQuery methods to remove the inline style(s), especially for the "display" property, and add a class. In the case of the hide method, which isn't an animation method, it can be simply replaced with class switching. Also you might consider avoiding the aforementioned methods in jQuery and use CSS3 transitions with class switching instead where you want an animation to occur.

Oh, how I wish we could have named breakpoints that are specified in a stylesheet to make it easier to not have to specify window dimensions in scripts.
0
 

Author Comment

by:Al4ddin2
Comment Utility
Thanks Kravimir. Yes that is correct, there are certain JQuery methods that will always apply inline styles so it's not like I am applying directly myself. But as for the image paths and maybe even hide/show, thanks for the advice, I will change them to addClass instead and apply the styles in my CSS instead.
Is there a better way than checking the window.width on resize though? Or is that really the only way to detect changes?

Thank you for the information though, it is very interesting and beneficial.
0
 
LVL 42

Expert Comment

by:David S.
Comment Utility
You're welcome.

I use ".is(':hidden')" sometimes, for example to check if the non-mobile main navigation is visible or not. "window.matchMedia()" can also be used to directly test media queries with JavaScript, but IE9 and older don't support it.
0
 
LVL 53

Expert Comment

by:COBOLdinosaur
Comment Utility
The fact that a lot of jquery libraries use inline styles is one of the reasons I only use jquery as a last resort.  

When it come to CSS, most of what jquery does is make what would be a 30 second change to a stylesheet into a week long journey to the depths of hades trying to figure out what the author did to prevent a simple change.

 There is very little That jquery can do that I cannot do better myself using technology that does not break the Document Object, limit options, and add substanstial time for simple maintenance.  Plus I can rely on standards based technology, as opposed to the chaos of "anything goes" with jquery.

Cd&
0
 

Author Comment

by:Al4ddin2
Comment Utility
Although your comment was helpful in seeing how good you are at other technologies, would you mind offering advice instead?
0
 
LVL 53

Expert Comment

by:COBOLdinosaur
Comment Utility
would you mind offering advice instead?

I did.  You are just not interested in hearing anything that does not fit in with the self-limiting path you are on. You need to ask questions to figure out how to do some things.  I don't have to ask questions because I have already explored the range of technologies and know how to do things in the most efficient and sustainable way.  

I sometimes offer advice on professional development to my students and to users of other tech sites I support. Whether or not my advice gets followed does not make any difference to me; but I have managed to answer 7000+ questions here and several thousand on other sites, so sometimes I guess my advice is seen to have some value.

Cd&
0
 

Author Comment

by:Al4ddin2
Comment Utility
I am sure you a a very wise person and knowledgeable in your subject areas, hence why you're on here answering queries.
My comment was not meant to offend but rather for you to let me know what some of these alternative technologies are that you would use before jquery. Rather than you just saying you would use 'them'.
As an example, how would you approach a scenario where you have an element that is hidden in mobile and not in desktop that when in mobile view has an on click event that adds a slide down transition but this needs removing for desktop. Happy to add this in a new thread if you wish for the points. Thank you b
0
 
LVL 53

Expert Comment

by:COBOLdinosaur
Comment Utility
I don't need points.  I already have enough to sink an aircraft carrier.  

When you have differences in how rendering needs to be done on different devices then using media queries with alternate stylesheets will generally handle the differences with little or no scripting.  Even if the content presentation itself must be altered it can almost always be handled with media queries in the CSS.

Something as simple as different rendering for portrait and landscape orientation should never require anything more than a media query that responds to the change and switches to the alternate rendering.

It is simply a matter of showing the user only the elements appropriate for the conditions under which they are accessing, and hiding those things that are not appropriate.  That is what CSS is for.

Learn about media queries here:
https://developer.mozilla.org/en-US/docs/CSS/media_queries

Cd&
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
Nothing in an HTTP request can be trusted, including HTTP headers and form data.  A form token is a tool that can be used to guard against request forgeries (CSRF).  This article shows an improved approach to form tokens, making it more difficult to…
In this tutorial viewers will learn how to style a corner ribbon overlay for an image using CSS Create a new class by typing ".Ribbon":  Define the class' "display:" as "inline-block": Define its "position:" as "relative": Define its "overflow:" as …
The viewer will learn how to dynamically set the form action using jQuery.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now