Is Javascript an Effective Method of Creating Fluid Layouts? - javascript

I'd like opinions on whether or not Javascript is a still a viable and relatively effective method of producing fluid website layouts. I know that it is possible to create fluid layouts with Javascript, but relative to other methods (e.g. CSS3/HTML5) how does it stand up in terms of performance and complexity? The function below represents what I mean. In the function, javascript is being used to find the dimensions of various elements and place other elements accordingly. To see it working, follow this link.
function onPageResize() {
//center the header
var headerWidth = document.getElementById('header').offsetWidth; //find the width of the div 'header'
var insideHeaderWidth = (document.getElementsByClassName('header')[0].offsetWidth + document.getElementsByClassName('header')[1].offsetWidth + document.getElementById('logoHeader').offsetWidth); //find the combined width of all elements located within the parent element 'header'
document.getElementsByClassName('header')[0].style.marginLeft = ((headerWidth - insideHeaderWidth) / 2) + "px"; //set the margin-left of the first element inside of the 'header' div
/////////////////////////////////////////////////////////////////
//justify alignment of textboxes
var subtitleWidth = document.getElementsByClassName('subtitle'); //assign the properties of all elements in the class 'subtitle' to a new array 'subtitleWidth'
var inputForm = document.getElementsByClassName('inputForm'); //assign the properties of all elements in the class 'inputForm' to a new array 'inputForm'
for (i = 0; i < inputForm.length; i++) { //for every element in the array 'inputForm' set the margin-left to dynamically place the input forms relative to eachother
inputForm[i].style.marginLeft = (subtitleWidth[4].offsetWidth - subtitleWidth[i].offsetWidth) + "px";
}
/////////////////////////////////////////////////////////////////
//place footer on absolute bottom of page
if (window.innerHeight >= 910) { //when the page is larger than '910px' execute the following
var totalHeight = 0; //initialize a new variable 'totalHeight' which will eventually be used to calulate the total height of all elements in the window
var bodyBlockHeight = document.getElementsByClassName('bodyBlock'); //assign the properties of all elements in the class 'bodyBlock' to a new array 'bodyBlockHeight'
for (i = 0; i < bodyBlockHeight.length; i++) { //for every instance of bodyBlockHeight in the array, add the height of that element into the 'totalHeight'
totalHeight += bodyBlockHeight[i].offsetHeight;
}
totalHeight += document.getElementById('header').offsetHeight; //finally, to add the height of the only element that has yet to be quantified, include the height of the element 'header' into the 'totalHeight'
/*Set the margin-top of the element 'footer' to the result of subtracting the combined heights of all elements in the window from the height of the window.
This will cause the footer to always be at the absolute bottom of the page, despite whether or not content actually exists there. */
document.getElementById('footer').style.marginTop = (window.innerHeight - totalHeight) - document.getElementById('footer').offsetHeight + "px";
} else {
//if the page height is larger than 910px (approx the height of all elements combined), then simply place the footer 20px below the last element in the body
document.getElementById('footer').style.marginTop = "20px"
}
/////////////////////////////////////////////////////////////////
}
Again, the result of the above function can be viewed at this link.
Thank you to any and all who offer their opinions!

You should be using CSS rather than JavaScript because that is what CSS is designed to do. If you want a fluid layout play around with using percentage widths, floats and media queries.

Related

why doesn't my JS function fire on the onresize event?

function getCentralPosition() {
// This script verticaly centers the heading you see on the main home page video //
// First save the parent div that houses the heading element into a variable named parentDiv.
var parentDiv = document.getElementById('home-section-1');
// Now obtain the total height (including padding, borders etc) of this parentDiv
var parentDivHeight = parentDiv.offsetHeight;
// Save the child div element that houses the heading into a variable named childDiv
var childDiv = document.getElementById('home-first-overlay');
// Now obtain the total height (including padding, borders etc) of this childDiv
var childDivHeight = childDiv.offsetHeight;
// Calculate the height difference between the parentDiv and childDiv by subtracting their heights and storing them
// in a variable named heightDiff
var heightDiff = parentDivHeight - childDivHeight;
// Obtain the precise position required from the top of the parentDiv by dividing heightDiff by 2
var pos_from_top = heightDiff / 2;
// assign pos_from_top as the value for 'top' on childDiv using "px"
childDiv.style.top = pos_from_top + "px";
}
window.addEventListener("onresize", getCentralPosition);
without the window resize eventlistener, I used the code as is - but the idea is that it also stays in the center when one trys to resize the browser window etc. Thought not necessary, i just wanted to achieve this. Any ideas as to what I should be trying ?
I believe you are looking for the "resize" event
Here is the updated snippet (it errors without the proper HTML, but shows the event firing).
function getCentralPosition() {
// This script verticaly centers the heading you see on the main home page video //
// First save the parent div that houses the heading element into a variable named parentDiv.
var parentDiv = document.getElementById('home-section-1');
// Now obtain the total height (including padding, borders etc) of this parentDiv
var parentDivHeight = parentDiv.offsetHeight;
// Save the child div element that houses the heading into a variable named childDiv
var childDiv = document.getElementById('home-first-overlay');
// Now obtain the total height (including padding, borders etc) of this childDiv
var childDivHeight = childDiv.offsetHeight;
// Calculate the height difference between the parentDiv and childDiv by subtracting their heights and storing them
// in a variable named heightDiff
var heightDiff = parentDivHeight - childDivHeight;
// Obtain the precise position required from the top of the parentDiv by dividing heightDiff by 2
var pos_from_top = heightDiff / 2;
// assign pos_from_top as the value for 'top' on childDiv using "px"
childDiv.style.top = pos_from_top + "px";
}
window.addEventListener("resize", getCentralPosition);
I use a similar function to adjust a dynamic svg graph based screen size.
I just place the onresize="function()" code in the tag and it works out of the box.

How do I set the height of a css element based on the randomly generated height of another element?

I'm trying to create a consistent gap of 100px between two 'walls', one on the top of the screen 'wallTop' and one on the bottom 'wallBot', like in Flappy Bird. I've used Math.random on 'wallTop' to randomise the height of it in order to randomise the position of the gap, but how do I set the height of 'wallBot' to be based off of 'wallTop's randomised height?
Here's what I've tried
var wallGap = 100;
var wallTop = document.getElementById("wallTop");
var constant= (wallTop.height+wallGap);
$("#wallTop").css("height",Math.round(Math.random()*150+70)+"px");
$("#wallBot").css("height",450-constant+"px");
"450" is the height of the whole container, so I'm trying to find the remainder after subtracting 'wallTop' and 'wallGap', which will be the height of 'wallBot'.
Your constant won't change magically after having set a new height for wallTop (also note that wallTop.height will be undefined, since the element doesn't have the property height).
var wallGap = 100;
var wallSpace = 450 - wallGap;
var wallTop = $("#wallTop");
var wallBot = $("#wallBot");
wallTop.height(Math.round(Math.random()*150+70));
wallBot.height(wallSpace - wallTop.height());

why the width of elements are different after page load and after that moment?

The situation is that I want to change the size of an element right after the page load. The problem is that the element did not change because the result returned by the function getSearchBarWidth was negative number. Something strange here is that console prints incorrect values of the width of the two element web_logo and menu; their width should be small, but in the console, the width of both elements are equal the parent element, which is a navigation bar. But later, I print out again the width of two element in console, the result was correct. Can someone explain this?
update: it seems because I don't specify the width of the navigation bar. So is there any other except specify the width of the parent element to get the correct width of its children right after page loads?
<script src="js/function.js" defer></script>
Content of file js
// calculate the width of window and relevant element
function getSearchBarWidth(){
var wWidth = $(window).width();
var offset = 20; // distance between the search bar and each of the two next elements
var offset_1 = 15; // padding of each sides of the navi bar
var searchBarWidth = wWidth - $("#navi_bar > .web_logo").width() - $("#navi_bar > .menu").width() - 2*offset - 2*offset_1;
return searchBarWidth;
}
// change the size of search bar
if($("#navi_bar > .search_bar").length > 0){
console.log("window: "+ $(window).width());
console.log("logo: "+ $("#navi_bar > .web_logo").width());
console.log("menu: "+ $("#navi_bar > .menu").width());
$("#navi_bar > .search_bar").css("width", getWindowWidth());
}
My problem is solved. Just call setTimeout and then the width of element would be correct.

Problems calculating the actual height of web page elements with Javascript and JQuery?

I am modifying some code I found for paginating HTML content into a div. The code is from the jQuery rain site found on this page:
http://www.jqueryrain.com/?HtS47Rzc
The intent of this code is to take a large chunk of HTML, scan the top level child elements, and create a page object for each group of child elements that fit within a desired height (E.g. 400px). Once all the pages are built, each page is wrapped in a new div. The problem I'm having is that the calculated pages aren't close to the desired height once rendered to the page. So instead of each page having a nice block of text that neatly bumps into but does not exceed the bottom of the containing div, some pages have text falling far short of the desired page bottom and some exceed the page bottom. Actually they no longer exceed the page bottom since I added code that scans the pages array after each page has been wrapped with a div and sets the container div to the maximum div height found.
One thought I had is that the wrapping of the div was causing the variance so I explicitly added CSS rules to set the margins and padding to 0px. That had no effect. Can anyone tell me how to adjust the code so that the page height calculations work properly?
UPDATE: I'm showing the CSS for the div that holds a page and the DIV that contains it.
.example{
background:#FFF;
width:410px;
border:1px #000 solid;
margin:20px auto;
padding:15px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px
}
The page divs all have the class of "page":
#content .page {
position:absolute;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
top:0px;
}
Here is my Javascript modified code. Note, the object being processed by the function is the main div that shows the paginated content:
(function ($) {
$.fn.extend({
MyPagination: function (options) {
var defaults = {
height: 400,
fadeSpeed: 400
};
var options = $.extend(defaults, options);
//Creating a reference to the object
var objContent = $(this);
// The array of pages we will build.
var fullPages = new Array();
// The array of elements for each page, used during pagination calculations.
var pageElements = new Array();
// The height for each page, reset after each page is built.
var height = 0;
var lastPage = 1;
var paginatePages;
// initialization function
init = function ()
{
// Build the array of pages by creating a new page when the sum of the child elements
// height values for each page exceeds the desired page height.
//
// NOTE: This is only an approximation. Haven't figured out why yet. When the
// operation is done there is large variance in the DIV height away from our desired
// height, many of them larger than our desired height.
objContent.children().each(function (i)
{
// Some browsers don't support clientHeight. In those cases, use offsetHeight.
var childHeight = this.clientHeight == 0 ? this.offsetHeight : this.clientHeight;
// If the height of all the children in the page elements array exceeds the desired
// page height, start a new page.
if (height + childHeight > options.height)
{
// Start a new page.
fullPages.push(pageElements);
// Reset the page elements array by initializing it to a new array.
pageElements = new Array();
// Reset the page height accumulatore. for the next page.
height = 0;
}
// Accumulate the child element's height into the height aggregator variable.
height += childHeight;
// Add the child element to the child elements array for the page currently being built.
pageElements.push(this);
});
if (height > 0) {
fullPages.push(pageElements);
}
// wrapping each full page
// $(fullPages).wrap("<div class='page'></div>");
// Wrapping each full page with a DIV. Give the DIV an ID that contains the page number.
$(fullPages).wrap(
function (ndx) {
return "<div class='page' name='pages' id='page_" + (ndx + 1) + "'></div>"
});
// Find the DIV with the maximum height.
var maxDivHeight = 0;
for (var ndx = 1; ndx <= fullPages.length; ndx++) {
var pageN = document.getElementById('page_' + ndx);
// Some browsers don't support clientHeight. In those cases, use offsetHeight.
var divHeight = pageN.clientHeight == 0 ? pageN.offsetHeight : pageN.clientHeight;
if (divHeight > maxDivHeight)
maxDivHeight = divHeight;
}
// Set the height of the content DIV to the maximum height we found plus a little padding.
objContent.height(maxDivHeight);
// hiding all wrapped pages
objContent.children().hide();
// making collection of pages for pagination
paginatePages = objContent.children();
// show first page
showPage(lastPage);
// draw controls
showPagination($(paginatePages).length);
};
// update counter function
updateCounter = function (i) {
$('#page_number').html(i);
};
// show page function
showPage = function (page) {
i = page - 1;
if (paginatePages[i]) {
// hiding old page, display new one
$(paginatePages[lastPage]).fadeOut(options.fadeSpeed);
lastPage = i;
$(paginatePages[lastPage]).fadeIn(options.fadeSpeed);
// and updating counter
updateCounter(page);
}
};
// perform initialization
init();
}
});
})(jQuery);
You can maybe use getBouningClientRect on your element. This will give you the position and size of that element:
var clientRect = element.getBoundingClientRect();
And now you can get the size and position:
var leftPos = clientRect.left;
var topPos = clientRect.top;
var width = clientRect.width;
var height = clientRect.height;
Hope this helps!
Here is a link to more information: https://developer.mozilla.org/en-US/docs/Web/API/element.getBoundingClientRect

Getting Coordinates of an element on page scroll

I am having this problem where i have a set of 6 UL's having a common class x.Each of them consist of a specific section of the page.Now i have 6 menus that are related to each of the section.What i have to do is highlight the menu when its related section is in users view.
For this i thought that may be jQuery position(); or offset(); could have helped but they give the top and left of the element.I also tried using jQuery viewport plugin but apparently view port is big it can show more than one UL at a time hence i cant apply element specific logic here.I am not familliar to this but does anything changes of an element on scrolling?If yes then how to access it?
Please share your views.
Regards
Himanshu Sharma.
Is very easy to do it using jQuery and a dummy fixed HTML block that helps you find the current position of the viewport.
$(window).on("scroll load",function(){
var once = true;
$(".title").each(function(ele, index){
if($(this).offset().top > $("#viewport_helper").offset().top && once){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
once = false;
}
});
})
Check out a working example: http://jsfiddle.net/6c8Az/1/
You could also do something similar with the jQuery plugin, together with the :first selector:
$(window).on("scroll load",function(){
$(".title:in-viewport:first").each(function(){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
});
})
You can get the viewport's width and height via $(document).width() and $(document).height()
You can get how many pixels user scrolls via $(document).scrollTop() and $(document).scrollLeft
Combining 1 and 2, you can calculate where the viewport rectangle is
You can get the rectangle of an element using $(element).offset(), $(element).width() and $(element).height()
So the only thing left to you is to determine whether the viewport's rectangle contains (or interacts) the elements's rectangle
So the whole code may look like:
/**
* Check wether outer contains inner
* You can change this logic to matches what you need
*/
function rectContains(outer, inner) {
return outer.top <= inner.top &&
outer.bottom >= inner.bottom &&
outer.left <= inner.left &&
outer.right >= inner.right;
}
/**
* Use this function to find the menu related to <ul> element
*/
function findRelatedMenu(element) {
return $('#menu-' + element.attr('id'));
}
function whenScroll() {
var doc = $(document);
var elem = $(element);
var viewportRect = {
top: doc.scrollTop(),
left: doc.scrollLeft(),
width: doc.width(),
height: doc.height()
};
viewportRect.bottom = viewportRect.top + viewportRect.height;
viewportRect.right = viewportRect.left + viewportRect.width;
var elements = $('ul.your-class');
for (var i = 0; i < elements.length; i++) {
var elem = $(elements[i]);
var elementRect = {
top: elem.offset().top,
left: elem.offset().left,
width: elem.width(),
height: elem.height()
};
elementRect.bottom = elementRect.top + elementRect.height;
elementRect.right = elementRect.left + elementRect.width;
if (rectContains(viewportRect, elementRect)) {
findRelatedMenu(elem).addClass('highlight');
}
}
}
$(window).on('scroll', whenScroll);
Let's see if i understood well. You have a page long enough to scroll, and there is an element that when it appears in the viewport, you wanna do something with it. So the only event that's is triggered for sure on the time the element gets in the viewport is the 'scroll'. So if the element is on the page and the scroll is on the viewport, what you need to do is bind an action to the scroll event to check if the element is in the view each time the event is trigger. Pretty much like this:
$(window).scroll(function() {
check_element_position();
});
Now, in order for you to know if the element is in the viewport, you need 3 things. The offset top of that element, the size of the viewport and the scroll top of the window. Should pretty much look like this:
function check_element_position() {
var win = $(window);
var window_height = win.height();
var element = $(your_element);
var elem_offset_top = element.offset().top;
var elem_height = element.height();
var win_scroll = win.scrollTop();
var pseudo_offset = (elem_offset_top - win_scroll);
if (pseudo_offset < window_height && pseudo_offset >= 0) {
// element in view
}
else {
// elem not in view
}
}
Here, (elem_offset_top - win_scroll) represent the element position if there was no scroll. Like this, you just have to check if the element offset top is higher then the window viewport to see if it's in view or not.
Finally, you could be more precise on you calculations by adding the element height (variable already in there) because the code i just did will fire the event even if the element is visible by only 1 pixels.
Note: I just did that in five minutes so you might have to fix some of this, but this gives you a pretty darn good idea of what's going on ;)
Feel free to comment and ask questions

Categories

Resources