Dynamically percentage width assignment with jQuery - javascript

I've got a simple piece of jQuery running to assign a width to my list items:
$(subMenu).each( function() {
var noLi = $(this).children('li').length,
itemSize = (10/noLi)*10;
$(this).children('li').each( function() {
$(this).css('width', itemSize +'%');
});
});
I know there are always less than 10 list-items in this case so I am generating the percentage width by the simple itemSize calculation. However if more items were added, the whole thing would fail & the layout would not be as intended.
I also believe this may not be the most efficient way to achieve this in the first place, but am unsure of a better way. Can someone point me in the right direction?

You mean itemSize gets to big? If so, you can do this:
itemSize = Math.min(100, (10/noLi)*10); // Get smallest value of the two. 100 is the max now
About adding sizes, you can replace the code to this:
$(this).children('li').css('width', itemSize +'%'); // no need for each
Combined would be:
$(subMenu).each( function() {
var $AllLi = $(this).children('li'); // Save'm all for later access
var noLi = $AllLi.length; // we saved all selected li´s so we dont need to reselect
itemSize = Math.min(100, (10/noLi)*10);
$AllLi.css('width', itemSize +'%'); // no need for each
});
Another way might be better, using css:
<style>
ul{
width: 100%;
display: table-row;
}
li{
display: table-cell;
}
li:gt(10){
display: none;
}
</style>
<ul>
<li>li part</li>
<li>li part</li>
<li>li part</li>
<li>li part</li>
</ul>

First, you don't need to make any assumptions about how many items you're going to have. If you just want to divide the 100% width into x number of items, you can simply use 100 / x.
Also, there is no need for the nested .each you have. jQuery does that automatically.
$(subMenu).each(function() {
var items = $(this).children('li');
var itemSize = 100 / items.length;
items.css('width', itemSize +'%');
});

Related

Count visible elements in a scrolled div

I would like to calculate how many items are visible (including the last one visible even if there is 10px shown) in a scrollable div to animate it in an AJAX callback transition.
Depending on screens sizes, that can vary and I'm looking for detect that.
The goal is to do something like that (but I don't know the lt(n))
$(".box:lt(n)")...
Example:
— http://jsfiddle.net/gy4uLu7x/
This code will do
$(function () {
var total_width = $(".box").length * $(".box").outerWidth(true);
$(".scroll").width(total_width);
var scroll = $('.scroll');
var viewport_w = scroll.parent().width();
var box1 = $('.box:first');
var boxw = box1.outerWidth(true);
var view_items = Math.ceil(viewport_w/ boxw);
console.log(boxw, viewport_w, view_items);
});
this code works on the fact that all boxes' (outer)width is equal. It calculates with of the immediate parent of .scroll which happens to be the body element and checks how many elements will fit into it. It converts the decimal part of the division result into and integer to accommodate for your _ even if there is 10px shown_ requirement. i.e., even 0.1 is converted into a 1.
Update
margin collapse won't happen :D
Calculate the width of scroll's parent (since this is the "viewport" in this case). Then count the boxes that start at a position less than above calculated width. This will work only in the above mentioned scenario.
var parentContainerWidth = $(".scroll").parent().width();
var containedBoxesCount = $('.box').filter(function () {
return $(this).offset().left <= parentContainerWidth;
}).length;
alert(containedBoxesCount);
Here is a demo

Get the first Element that is floating on next line

I have a list of Elements that are floating left:
<style>
ul {
overflow: hidden;
width: 100%;
}
ul li {
float: left;
width: 100px;
}
</style>
<ul>
<li id="#one">One</li>
<li id="#two">Two</li>
<li id="#three">Three</li>
...
</ul>
...having a window width of 200px the first Element that is floating on the second line would be #three... having a window width of just 100px that would be #two.
Now on every <li> there is a click-event bound, that should tell me which Element is the first Element on the next Line, seen by itself.
Clicking on #one with a window width of 200px I want to get #three, and with a window width of 100px I want to get #two.
I tried to solve this by getting the position of the Element that is clicked on, query the Position inside the window using .getBoundingClientRect(), get the height of the Element (taking 20px here), and then get the Element by using document.elementFromPoint(y,x)...something like this:
y = clicked_element.getBoundingClientRect().left
x = clicked_element.getBoundingClientRect().top + 21
first_element_on_next_line = document.elementFromPoint(y,x)
so far, so good... but of course this is just working if the first element on the next line is really inside the window! :-\
and this is where I'm stuck...if I have a window width of 200px and a window height of just 20px (just for the example), I just can't select #three with document.elementFromPoint() because its position is outside the window.
I could also use jQuery, it's included anyways, but everything came across was using document.elementFromPoint()
Any Ideas??
You could use following logic using jQuery .position() method: {as suggested by maja}
$(function () {
var $lis = $('ul li').on('click', function(){
var $nextFirstElement = $(this).nextAll('.first').first();
console.log($nextFirstElement);
});
$(window).on('resize', function () {
var initialLeft;
$lis.each(function(i){
if (i === 0) { // this could be put out of the loop, but...
initialLeft = $(this).position().left;
}
$(this).toggleClass('first', i === 0 || $(this).position().left === initialLeft);
});
}).resize();
});
-jsFiddle-
The Solution I'm using now (which in fact is the Solution charlietfl brought up in the Comments) is this:
$(function(){
var list = $("ul"),
lis = list.children(),
first_li = lis.first(),
list_width, first_li_width, items_per_line
var set_vars = function(){
list_width = list.width()
first_li_width = first_li.width()
items_per_row = Math.floor(list_width / first_li_width)
}
set_vars()
lis.click(function(){
index = lis.index(this)
next_first_index = index + (items_per_row - (index % items_per_row))
console.log(next_first_index)
})
$(window).resize(function(){
set_vars()
})
})

How to measure and set the width?

I would like to make sub-navigation to measure its parents width and then set its own width accordingly. At the moment every sub-navigation (.primary-navigation ul ul) gets an individual class (customWidth-0 + i). Then using this class I measure its parent's width and set the width minus the padding. It's all working nice and fine, but I'm learning and I'd like to shorten the script. I was trying to loop this, use "this", but seem to get stuck at every point. It would be nice to learn to do this in a proper, robust way. Any help is very much appreciated. Thanks.
jQuery(document).ready(function( ) {
jQuery(".primary-navigation ul ul").each(function(i) {
i = i+1;
jQuery(this).addClass("customWidth-0" + i);
});
a = jQuery(".customWidth-01").prev().parent().width();
b = jQuery(".customWidth-02").prev().parent().width();
c = jQuery(".customWidth-03").prev().parent().width();
d = jQuery(".customWidth-04").prev().parent().width();
jQuery(".customWidth-01").css("width", a-31);
jQuery(".customWidth-02").css("width", b-31);
jQuery(".customWidth-03").css("width", c-31);
jQuery(".customWidth-04").css("width", d-31);
});
I took your look and added my code after commenting your sections out and got the same thing.
<script type="text/javascript">
jQuery(document).ready(function( ) {
jQuery(".primary-navigation ul ul").each(function(i) {
i = i+1;
var _this = jQuery(this), w = _this.parents('ul').width();
_this.css("width", (w-31)+"px");
//jQuery(this).addClass("customWidth-0" + i);
console.log(i);
});
/*
a = jQuery(".customWidth-01").prev().parent().width();
b = jQuery(".customWidth-02").prev().parent().width();
c = jQuery(".customWidth-03").prev().parent().width();
d = jQuery(".customWidth-04").prev().parent().width();
jQuery(".customWidth-01").css("width", a-31);
jQuery(".customWidth-02").css("width", b-31);
jQuery(".customWidth-03").css("width", c-31);
jQuery(".customWidth-04").css("width", d-31);
*/
});
</script>
It will find the div above given ul and take its width take off 31px and then apply it to given elements below. The LI elements inside of the UL will already have a 100% width and conform to that standard. If you wanted to you could just apply a position: relative; on the LIs of the .primary-navigation and then position: absolute; left: 0; top: ~20px; (top is a little skewed according to your em size.. This will do the same thing except it won't wrap your children and make it look weird.
If you gave me an exact image of what you wanted your menu to look like (not using javascript or anything maybe a designed version??) I could probably do a better job as this is still kinda hard to answer. Hopefully the code I provided helps you if not leave another comment and let me know if you have questions.
Below line is old answer.
Set a variable
var _this = jQuery(this), w = _this.parent().parent().width();
_this.css("width", (w-31)+"px");// just to be safe added px use w/e or leave blank it assumes it
This should work for you the same as you have it in the foreach.
you could also use .parents('ul')
w = _this.parents('ul').width();
function() {
$('.primary-navigation').children('li').each(
function(index) {
var parentWidth = $(this).width();
$(this).children('ul').width(parentWidth/2);
}
);
Is this what you are looking for? now all the sub menu is 1/2 of parent. you need to fix it to your specific need.
DEMO http://jsfiddle.net/La07pvf2/

jQuery calculating 2 different HTML element attributes (height + margin-bottom)

I'm trying to get the height and the margin-bottom of a element, and count them up. But so far, i can only do this:
var sum = $('div').height() + 25);
That 25 i had to look up myself in the stylesheet at
div {
height: 75px;
margin-bottom: 25px;
}
How can i make this automaticly?
Because when i try:
var sum = $('div').height() + $('div').css('margin-bottom');
It isnt returning any value.
You're probably looking for http://api.jquery.com/outerheight/ which includes the margins, padding and borders (all which count towards the total height, along with the base height). Alternatively, you can use parseInt($('div').css('margin-bottom')) because the value is a css string that looks something like this: 100px. parseInt() would extract the 100 from that css, which is what you want.
In addition, you're kinda doing it wrong in general. Are you looking for the sum of all the heights of all the div elements? Or does your page have only one div?
$('div').css('margin-bottom') will have the px attached. Try and use something like parseInt()
var sum = $('div').height() + parseInt($('div').css('margin-bottom'), 10);
W
There are many 'div' elements in a document(usually).
You need a better selector for the one you want.
Fiddle for value in console.log
<div id="TestId" class="test"></div>
.test
{
height:40px;
margin:5px;
}
var tester = $("#TestId");
var eleHeight = tester.outerHeight();
var marginBottomHeight = tester.css('margin-bottom').replace("px", "")
console.log(eleHeight + parseInt(marginBottomHeight));

Javascript to turn an unordered list into multiple columns

There doesn't seem to be an easy way in (well supported) css to do this. I'm looking for a javascript solution, preferably jQuery.
I have an unordered list like this:
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<li>E</li>
...etc
</ul>
I want each column to have a height for example four items and fill vertically rather than horizontally like a css float:
A E
B F
C
D
You will want to use a combination of CSS and jQuery, but in theory it is very simple. Render a complete single list in HTML, then provide a wrapper via jQuery and split the list up as desired. The following function does just that. Be sure to use a more specific selector than just ul when actually using the script. An id would be ideal.
View demo here.
jQuery(function ($) {
var size = 4,
$ul = $("ul"),
$lis = $ul.children().filter(':gt(' + (size - 1) + ')'),
loop = Math.ceil($lis.length / size),
i = 0;
$ul.css('float', 'left').wrap("<div style='overflow: hidden'></div>");
for (; i < loop; i = i + 1) {
$ul = $("<ul />").css('float', 'left').append($lis.slice(i * size, (i * size) + size)).insertAfter($ul);
}
});
See this article:
One of the minor holy grails of XHTML
and CSS is to produce a single,
semantically logical ordered list that
wraps into vertical columns.
I’ll warn you up front. If you want to
present a list in multiple columns,
you’ll have to compromise. You can
sacrifice W3C web standards and use
deprecated markup, you can live with
markup that’s less than semantically
logical, you can tolerate a mixture of
presentation with content, you can say
goodbye to browser compatibility, or
you can use markup that’s heavy with
attributes and styling that’s heavy
with rules. Every road exacts a toll.
http://www.alistapart.com/articles/multicolumnlists/
The "best" solution is subjective, but I'd be inclined towards arbitrary classes.
Doug's solution is nice if you want to split the list up into sub lists.
Instead I chose to position the list elements without changing the dom.
This is a bit messy, basically it puts a left margin on each element which is the column number multiplied by the column width.
This will result in a staircase layout so the next step was to add some negative top margin to bring each element up to the top.
Basically this displays as a grid. I am using this for drop down menus so it worked well. Avoid using this if you need each list item to have a dynamic height. The col_height variable could be set to the height of the largest item to make the code a bit more general purpose.
var col_max_height = 6; //Max Items per column
var col_width = 200; //Pixels
var col_height = 33; //Pixels
$('.header ul li ul').each(function() {
$(this).find('li').each(function(index){
column = parseInt(index/col_max_height);
$(this).css('margin-left', column * col_width + 'px')
if(column > 0) {
$(this).css('margin-top', (index - (col_max_height * column) + 1) * -col_height + 'px').addClass('col_'+column);
}
});
});
#Keyo, thanks for your helpful answer.
Just a few modification needed to make it work on my end.
(Formula was changed, perhaps it could help someone)
var col_max_item = 2; //Max Items per column
var col_width = $('.header ul li').css('width').replace("px", ""); //Pixels, get width from CSS
var col_height = $('.header ul li').css('height').replace("px", ""); //Pixels, get height from CSS
$('.header ul').each(function() {
$(this).find('li').each(function(index){
column = parseInt(index/col_max_item);
$(this).css('margin-left', column * col_width + 'px')
if(column > 0 && (index / col_max_item) == column) {
$(this).css('margin-top', (col_max_item * col_height * -1) + 'px').addClass('col_'+column);
}
});
});
for this I use a plugin called "Easy List Splitter". here is the link:
http://www.madeincima.it/en/articles/resources-and-tools/easy-list-splitter-plugin/
Just a little different moves up the next column instead of each li.
var col_max_height = 6; //Max Items per column
var col_width = 120; //Pixels
var prevCol = 0;
$('.header ul').each(function() {
$(this).find('li').each(function(index){
column = parseInt(index/col_max_height);
$(this).css('margin-left', column * col_width + 'px')
if(prevCol != column) {
$(this).css('margin-top', '-92px').addClass('col_'+column);
prevCol = column;
} else {
$(this).css('margin-top', '0px').addClass('col_'+column);
}
});
});
You can do this really easily with the jQuery-Columns Plugin for example to split a ul with a class of .mylist you would do
$('.mylist').cols(2);
Here's a live example on jsfiddle

Categories

Resources