“How can I make an element stretch full window width when it lives within a parent container with a set max width/fixed width?”
While the simplest approach is usually the best approach, there comes a time when we are all stuck with the rigid structure of the code we’re working on (i.e. code that hates you), with little-to-no wiggle room for tweaking that output. The obvious approach is to close up your parent container(s) and just do a width: 100%; in CSS for our full-width block, but this is, of course, assuming we have control enough to do that.
When it came time for me to build something full window width with a section that was already embedded in multiple other parent containers with hard set widths that I could not easily alter in any manner, you can see that times like these call for some smoke and mirrors of the jQuery kind.
In this case, we’ll use a parent container with a set width of 1200px, and a div that lives within this parent container that we want to stretch the full width of the window visually, but still want our content to show up within the confines of the parent width. For this example, let’s assume that our full-width section container will have the id full-width-block.
Window size on page load; settings variables:
The first thing we’ll need to do to get something useful is set a couple of variables on page load; first off the current size of the window itself, and secondly a variable to hold our logic for positioning of our #full-width-block.
Window width
Pretty self-explanatory what we’re doing here. Get the window width!
var window_width = $(window).width();
Positioning logic
This one is simple, but gets the important work done. Using our variable set above, window_width, we will need to calculate exactly the size of the offset in order to visually display our content in the correct place on the page. So we grab our window_width variable and subtract the parent container width from that (in this case 1020 pixels)
We then divide the remaining number by two since the remaining number after subtraction represents the margins that would be left on either side. Since we need to shift the content over by only one half of the remaining space, we make the final number negative. We also need to make sure that, since we’re dividing a number, that we only get a whole number returned, otherwise things may render with a potentially unsightly one pixel border on the edge. To combat this, we just need to round the half pixel by determining if the current screen width is an odd number.
Here’s a helper function we can use to help determine even/odd:
// Helper function - is a number even or odd? function isEven(num) { if(num !== false && num !== true && !isNaN(num)) { return num % 2 == 0; } else { return false; } }
We can then use this to figure out if we want to round our number for odd widths for use in our negative left margin. We’ll use the Math.ceil() Javascript method for this:
if(isEven(window_width) !== false) { var left_margin = -((window_width - 1200) / 2); // even } else { var left_margin = -(Math.ceil((window_width - 1200) / 2)); // odd }
Using our variables for output
This is where we actually get to use the variables. We’ll use the .width() and .css() jQuery functions to set our attributes as required, and alter the display of the #full-width-block div on the front-end. Specifically: setting .width() to our window_width variable and our .css() marginLeft to the negative left_margin variable we calculated. Pretty simple, right?
$('#full-width-block').width(window_width).css({ marginLeft : left_margin });
What if the window gets resized?
The code above all works perfectly as long as a user doesn’t touch their browser window width. But what if they do? You don’t really want this to break, so we’ll need to account for this with a little bit more logic of the same caliber.
Get window width after a resize
You’ll want to check what a user’s window width is again after any resize event takes place. If you don’t use the .bind() or .on() function, your jQuery may run before the resize event has completed and break your full-width div. This code binds the resize event to the window.
$(window).bind('resize', function(e) { if(window_width != $(window).width()) { // run through our logic again to determine element size and left margin offset } });
Functionalize it.
If we’re stuck inside of a rigid coding structure enough to have to do something like this in the first place, we’ll likely want to be able to easily do this again for more than one element. With that in mind, we’ll just throw together a simple function we can call for each element we want full width in the future.
function fullWidth(elementName, parentWidth) { var window_width = $(window).width(); // Determine whether to round up or not for odd widths if(isEven(window_width) !== false) { var left_margin = -((window_width - parentWidth) / 2); } else { var left_margin = -(Math.ceil((window_width - parentWidth) / 2)); } if(window_width > parentWidth) { elementName.width(window_width).css({ marginLeft : left_margin }); } else if(window_width < parentWidth) { elementName.css({ width : '100%' }, { marginLeft : '0' }); } // on window resize $(window).bind('resize', function(e) { if(window_width != $(window).width()) { var new_window_width = $(window).width(); // Determine whether to round up or not for odd widths if(isEven(new_window_width) !== false ) { var new_left_margin = -((new_window_width - parentWidth) / 2); } else { var new_left_margin = -(Math.ceil((new_window_width - parentWidth) / 2)); } if(new_window_width > parentWidth) { elementName.width(new_window_width).css({ marginLeft : new_left_margin }); } else if(new_window_width < parentWidth) { elementName.css({ width : '100%' }, { marginLeft : '0' }); } else { elementName.css({ width : '100%' }, { marginLeft : '0' }); } } }); }
We then just need to call the function and plug in the variables, in this case our element and the width of the parent container. We can call this for each element we want to make full width:
fullWidth($('#full-width-block'), '1200');
There you have it! You could further functionalize the repetitive code in this example too, if you so desire, but I just wanted to quickly illustrate a possible technique.
/***************************************** Full width element sorcery... ******************************************/ // Is the number even? function isEven( num ) { if( num !== false && num !== true && !isNaN( num ) ) { return num % 2 == 0; } else { return false; } } function fullWidth( elementName, parentWidth ) { var window_width = $(window).width(); // Determine whether to round up or not for odd widths if( isEven( window_width ) !== false ) { var left_margin = -((window_width - parentWidth) / 2); } else { var left_margin = -(Math.ceil((window_width - parentWidth) / 2)); } if ( window_width > parentWidth ) { elementName.width(window_width).css({ marginLeft : left_margin }); } else if ( window_width < parentWidth ) { elementName.css({ width : '100%' }, { marginLeft : '0' }); } widthHorz = $(window).width(); // on window resize $(window).bind('resize', function(e) { if ( widthHorz != $(window).width()) { var new_window_width = $(window).width(); // Determine whether to round up or not for odd widths if( isEven( new_window_width ) !== false ) { var new_left_margin = -((new_window_width - parentWidth) / 2); } else { var new_left_margin = -(Math.ceil((new_window_width - parentWidth) / 2)); } if ( new_window_width > parentWidth ) { elementName.width(new_window_width).css({ marginLeft : new_left_margin }); } else if ( new_window_width < parentWidth ) { elementName.css({ width : '100%' }, { marginLeft : '0' }); } else { elementName.css({ width : '100%' }, { marginLeft : '0' }); } } }); } function fullWidthRun() { if(current_body.hasClass('front')) { fullWidth($('.front .view-homepage-carousel .views-field-field-iframe'), site_width); } if(current_body.hasClass('section-the-denison-difference')) { fullWidth($('.node-type-life-after-denison .group-header'), site_width ); fullWidth($('.node-type-life-after-denison .group-studentdevelopment'), site_width ); fullWidth($('.node-type-life-after-denison .group-department-data'), site_width ); fullWidth($('.node-type-life-after-denison .group-tab-group'), site_width ); fullWidth($('.node-type-life-after-denison .group-five-year-out-cont .field-name-field-fiveyearout-impact'), site_width); } if(current_body.hasClass('section-a-to-z')) { fullWidth($('.section-a-to-z .filters .a-z-search-wrapper'), site_width ); } if(current_body.hasClass('section-series')) { fullWidth($('.section-series .taxonomy-term .group-header'), site_width ); } if(current_body.hasClass('section-people')) { fullWidth($('.section-people .group-contact-top'), site_width ); } if(current_body.hasClass('section-forms')) { fullWidth($('.section-forms .block-mefibs #edit-mefibs-form-search-by-name-t-wrapper'), site_width ); } if(current_body.hasClass('section-admissions') || current_body.hasClass('page-academics')) { fullWidth($('#block-block-26'), site_width ); } if(current_body.hasClass('section-campus-life')) { fullWidth($('#block-block-26'), site_width ); } if(current_body.hasClass('page-academics')) { fullWidth($('#block-block-31'), site_width ); } if(current_body.hasClass('page-node-48139') && current_body.hasClass('node-type-basic-page')) { fullWidth($('.page-node-48139.node-type-basic-page #main'), site_width ); } // Holiday break notification bar... Could be across any section fullWidth($('#block-block-25'), site_width ); } fullWidthRun();