when i view my website in mobile with lot of filters, the breadcrumb length becomes too large. so i want to replace all the li tags that are behind the second last li. that means all the li except first, last and last-1 li need to be replaced with dots.
Anybody can help me fix this with jquery, javascript, or css?
<ul class="left">
<li class="active">Airways</li>
<li>Trauma</li>
<li>Medical</li>
<li>OB | Peds</li>
<li>Patient Assessment</li>
<li>Proprietary</li>
<li>Trauma</li>
<li>Medical</li>
<li>OB | Peds</li>
<li>Patient Assessment</li>
<li>Proprietary</li>
</ul>
This is just example code i have added here.
You can try with jquery like this. Basically if it is a smaller width device, and if it is not first, last or second last child, the text of the link tag is replaced by '..' .
<script>
$(document).ready(function () {
if (window.matchMedia("(max-width: 767px)").matches)
{
// The viewport is less than 768 pixels wide
console.log("This is a mobile device.");
$('ul.left li').each(function() {
$this = $(this); // cache $(this)
if (! $this.is(':first-child') && ! $this.is(':nth-last-child(2)') && ! $this.is(':last-child') ) {
$this.find('a').text("..");
}
});
}
});
</script>
This is my first answer on stack overflow, hope this is what you want this is the codepen link
https:// codepen.io/vatzkk/pen/yLYMJeG
HTML
<script src="https://kit.fontawesome.com/a076d05399.js"></script>
<ul class="left" id="bread">
<li class="active">Airways</li>
<li id="dropdown" style="display:none">
<div class="dropdown" >
<i class="dropbtn">...</i><i class="fas fa-caret-down"></i>
<div class="dropdown-content" id="dropdown-list">
</div>
</div>
</li>
<li>Trauma</li>
<li>Medical</li>
<li>OB | Peds</li>
<li>Patient Assessment</li>
<li>Proprietary</li>
<li>Trauma</li>
<li>Medical</li>
<li>OB | Peds</li>
<li>Patient Assessment</li>
<li>Proprietary</li>
</ul>
Javascript
//you can add your conditions over here
document.getElementById("dropdown").style.display="block";
var arr=[...document.getElementById("bread").children];
var dropdownItems=arr.slice(2,-2);
dropdownItems.map(item=>{
document.getElementById("bread").removeChild(item);
document.getElementById("dropdown-list").appendChild(item);
});
Pure CSS Working example: https://jsfiddle.net/3o8vuwd6/2/
First give your list a class
<ul class="left breadcrumblist">
CSS:
/* This is just to give it some styling as you haven't given any */
.breadcrumblist li {
list-style: none;
display: inline-block;
padding-right: 0.5em;
}
.breadcrumblist li + li::before{
content: "/";
padding-right: 0.5em;
}
/* adjust to your breakpoint. 9999 just so it works on large screen as an example */
#media only screen and (max-width: 9999px) {
/* hide all */
.breadcrumblist li{
display: none;
}
/* show first and last */
.breadcrumblist li:first-child,
.breadcrumblist li:last-child{
display: inline-block;
}
/* add ... to the end of the first one */
.breadcrumblist li:first-child::after{
content: "...";
padding-left: 0.5em;
}
/* fiddle with the content we added in styling */
.breadcrumblist li + li::before{
content: "";
padding-right: 0;
}
}
Thank you all for your guidance and finally i made something work according to my requirement and also i want to share it here because in case in future if someone looks for the same issue he or she can be benefited from this. This is also from the modifications that all you have just posted above.
<ul class="left" id="bread_cumb">
$(document).ready(function(){
if (window.matchMedia("(max-width: 767px)").matches)
var width = $(window).width();
if (width < 720) {
$('#bread_cumb li:not(:first-child):not(:nth-child(2)):not(:last-
child):not(:nth-last-child(2))').html('<span style="margin-
left:7px;margin-right:7px;"> ... </span>');
var last =$('#bread_cumb li:last-child').text();
var re = /^([A-Za-z0-9_'",.!##$%^&*()-+=?/\|:]+)[\s,;:]+([a-z]+)/i;
var m = re.exec(last);
$('#bread_cumb li:last-child').html('<a>'+m[1]+' '+m[2]+'...</a>');
}
});
Thanks all for your valuable ideas.
I have trouble in writing a script to change the appearance of the clicked tab in a webpage navigation list. In other words, I want to make the clicked tab appear as the selected (in code). I tried to do that by changing its id to selected_link and restoring the id of the previously selected tab.
EDIT: Following jamespaned's suggestion, I replaced element IDs with classes.
My tabs appear like in this picture:
So, when I click to "bio", I want it to appear as "home" and "home" to appear as the other tabs.
As I'm a newbie in JavaScript coding, I didn't managed to accomplish that. Here is what I've done:
The HTML code for the (inline) navigation list:
<nav>
<ul id="navlist">
<li class="selected"> home </li>
<li class=""> bio </li>
<li class=""> publications </li>
<li class=""> software </li>
<li class=""> contact </li>
</ul>
</nav>
its respective CSS:
nav ul {
list-style:none;
padding:0;
margin:0;
}
nav li {
background-color:black;
display:inline;
border:solid;
border-width:1px 1px 0 1px;
margin:0 5px 0 0;
}
nav li a {
color:white;
padding:0 10px;
}
.selected {
background-color:white;
padding-bottom: 1px;
}
.selected_link{
color:blue;
}
and the JavaScript which I've designed to accomplish this task, but it didn't worked:
function changeSelected(clickedId)
{
var ulist = document.getElementById("navlist");
var elems = ulist.getElementsByTagName("class");
for (var i = 0; i < elems.length - 1; i++)
{
var sel = elems[i].getAttribute("class");
if (sel == selected)
{
var selli = elems[i];
break;
}
}
selli.setAttribute("class", "");
selli.lastElementChild.setAttribute("class", "");
var clicked = document.getElementById(clickedId);
clicked.setAttribute("class", "selected_link");
clicked.parentNode.setAttribute("class", "selected");
}
How could I do that using only plain JavaScript?
This Javascript will do what you want:
function changeSelected(clickedId)
{
var selli = document.getElementById("selected");
var sela = document.getElementById("selected_link");
sela.setAttribute("id", "");
selli.setAttribute("id", "");
var clicked = document.getElementById(clickedId);
clicked.setAttribute("id", "selected_link");
clicked.parentNode.setAttribute("id", "selected");
}
That said, here are some ideas that might help your Javascript education:
You are using Javascript to set your IDs, but the Javascript won't work on the next page after you've clicked on one of the links. You'll probably need to do some backend (PHP/Ruby, etc) coding to get your styles to change.
IDs are normally used to refer to a unique element on the page that doesn't change, such as a #header or #sidebar_banner. You might want to use a class instead, such as ".selected_link".
You don't need both #selected_link and #selected. You could do ".selected" and ".selected a" to change the CSS so you only need to change one element.
Hope that helps!
I got list of li tag that have 2 kinds of class name coding and design. The result that i want is if the li is design the post-link is display block and the site-link is display none while coding class name will have opposite effect. I store the li class into array then the condition will loop to find out what li tag have class name of design and coding. The result is the condition only read the last element of the array. Can you help me on this... sorry not good in asking question in english.
HTML
<li class="Design">
<a class="post-link"></a>
<a class="site-link"></a>
</li>
<li class="Design">
<a class="post-link"></a>
<a class="site-link"></a>
</li>
<li class="Coding">
<a class="post-link"></a>
<a class="site-link"></a>
</li>
var workArray = [];
var $work = jQuery('.slide-container li');
var $workClass = $work.attr('class');
$work.each(function(){
workArray.push($workClass);
for(i = 0; i < workArray.length; i++){
if(jQuery(this).hasClass('Design')){
jQuery('.post-link').css('display','block');
}else{
jQuery('.post-link').css('display','none');
}
}
});
css:
.Design .site-link {
display: none;
}
.Coding .post-link {
display: none;
}
and let the browser does the array/traverse push/pop by itself ;)
Just use relevant selectors and methods:
$('.Design .post-link').show(); // useless if not hidden by default
$('.Coding .post-link').hide();
Of course, you could just set CSS rules:
.Design .post-link { display: block;}
.Coding .post-link { display: none;}
It sounds like you are overcomplicating it.
I am trying to center a series of SPANs vertically inside their parent LIs.
The height values returned are all the same which means there must be something wrong with this code as some of the spans are on two lines.
Not sure if getting the height of an inline element (span) is a problem, any suggestions appreciated.
HTML:
<li class="nav-level-2-item">
<a href="">
<span class="menu-item">Text</span>
</a>
</li>
<li class="nav-level-2-item">
<a href="">
<span class="menu-item">Longer Text</span>
</a>
</li>
</ul>
JS:
$(document).ready(function () {
var navItem = $('li.nav-level-2-item');
navItem.each(function() {
var containerHeight = $('li.nav-level-2-item').height();
var spanHeight = $('span.menu-item').height();
alert(spanHeight)
$('span.menu-item').css('top', (containerHeight - spanHeight) / 2);
});
});
Making your span a block-level element will give it height:
<style> span.menu-item { display:block /* or inline-block */; } </style>
As an alternative, you could change the span to be one of the native block-level elements.
I'm not sure whether this is applicable to your code, but maybe you could avoid using jQuery altogether by making the <li> elements inline-block and centering them vertically:
li.nav-level-2-item
{
display: inline-block;
*display: inline; *zoom: 1; /* IE 6-7 hack */
vertical-align: middle;
}
Or another possible solution:
li.nav-level-2-item
{
display: table;
}
li.nav-level-2-item a
{
display: table-cell;
vertical-align: middle;
}
For additional CSS-only solutions, check out http://phrogz.net/css/vertical-align and http://www.vanseodesign.com/css/vertical-centering.
I'm not sure what the goal is, but I do have an answer for why the alert is always the same. You're iterating the li elements with .each(), but on each iteration, you aren't referencing the current item, so you always retrieve the height of the first matching element. Try this:
http://jsfiddle.net/5uwuQ/
$(document).ready(function () {
var navItem = $('li.nav-level-2-item');
navItem.each(function() {
var containerHeight = $(this).height();
var spanHeight = $('span.menu-item', this).height();
console.log(spanHeight)
});
});
Vertical centering of menu items is probably going to be easier by setting the line-height.
I'm using ColdFusion to populate a template that includes HTML unordered lists (<ul>s).
Most of these aren't that long, but a few have ridiculously long lengths and could really stand to be in 2-3 columns.
Is there an HTML, ColdFusion or perhaps JavaScript (I'm accepting jQuery solutions) way to do this easily? It's not worth some over-complicated heavyweight solution to save some scrolling.
So I dug up this article from A List Apart CSS Swag: Multi-Column Lists. I ended up using the first solution, it's not the best but the others require either using complex HTML that can't be generated dynamically, or creating a lot of custom classes, which could be done but would require loads of in-line styling and possibly a huge page.
Other solutions are still welcome though.
If Safari and Firefox support is good enough for you, there is a CSS solution:
ul {
-webkit-column-count: 3;
-moz-column-count: 3;
column-count: 3;
-webkit-column-gap: 2em;
-moz-column-gap: 2em;
column-gap: 2em;
}
I'm not sure about Opera.
There is no pure CSS/HTML way to achieve this, as far as I know. Your best bet would be to do it in pre-processing (if list length > 150, split into 3 columns, else if > 70, split into 2 columns, else 1).
The other option, using JavaScript (I'm not familiar with the jQuery library specifically) would be to iterate through lists, probably based on them being a certain class, count the number of children, and if it is a high enough number, dynamically create a new list after the first, transferring some number of list items to the new list. As far as implementing the columns, you could probably float them left, followed by an element that had the style clear: left or clear: both.
.column {
float: left;
width: 50%;
}
.clear {
clear: both;
}
<ul class="column">
<li>Item 1</li>
<li>Item 2</li>
<!-- ... -->
<li>Item 49</li>
<li>Item 50</li>
</ul>
<ul class="column">
<li>Item 51</li>
<li>Item 52</li>
<!-- ... -->
<li>Item 99</li>
<li>Item 100</li>
</ul>
<div class="clear">
I've done this with jQuery - it's cross-platform and a minimum of code.
Select the UL, clone it, and insert it after the previous UL. Something like:
$("ul#listname").clone().attr("id","listname2").after()
This will insert a copy of your list after the previous one. If the original list is styled with a float:left, they should appear side by side.
Then you can delete the even items from the left-hand list and the odd items from the right hand list.
$("ul#listname li:even").remove();
$("ul#listname2 li:odd").remove();
Now you have a left to right two column list.
To do more columns you'll want to use .slice(begin,end) and/or the :nth-child selector.
ie, for 21 LIs you could .slice(8,14) to create a new UL inserted after your original UL, then select the original UL and delete the li's selected with ul :gt(8).
Try the Bibeault/Katz book on jQuery it's a great resource.
Here is a variation on Thumbkin's example (using Jquery):
var $cat_list = $('ul#catList'); // UL with all list items.
var $cat_flow = $('div#catFlow'); // Target div.
var $cat_list_clone = $cat_list.clone(); // Clone the list.
$('li:odd', $cat_list).remove(); // Remove odd list items.
$('li:even', $cat_list_clone).remove(); // Remove even list items.
$cat_flow.append($cat_list_clone); // Append the duplicate to the target div.
Thanks Thumbkin!
The following JavaScript code works only in Spidermonkey and Rhino, and it operates on E4X nodes--i.e., this is useful only for server-side JavaScript, but it might give someone a starting point for doing a jQuery version. (It's been very useful to me on the server side, but I haven't needed it on the client badly enough to actually build it.)
function columns(x,num) {
num || (num = 2);
x.normalize();
var cols, i, j, col, used, left, len, islist;
used = left = 0;
cols = <div class={'columns cols'+num}></div>;
if((left = x.length())==1)
left = x.children().length();
else
islist = true;
for(i=0; i<num; i++) {
len = Math.ceil(left/(num-i));
col = islist ? new XMLList
: <{x.name()}></{x.name()}>;
if(!islist && x['#class'].toString())
col['#class'] = x['#class'];
for(j=used; j<len+used; j++)
islist ? (col += x[j].copy())
: (col.appendChild(x.child(j).copy()));
used += len;
left -= len;
cols.appendChild(<div class={'column'+(i==(num-1) ? 'collast' : '')}>{col}</div>);
}
return cols;
}
You call it like columns(listNode,2) for two columns, and it turns:
<ul class="foo">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
into:
<div class="columns cols2">
<div class="column">
<ul class="foo">
<li>a</li>
<li>b</li>
</ul>
</div>
<div class="column collast">
<ul class="foo">
<li>c</li>
</ul>
</div>
</div>
It's meant to be used with CSS like this:
div.columns {
overflow: hidden;
_zoom: 1;
}
div.columns div.column {
float: left;
}
div.cols2 div.column {
width: 47.2%;
padding: 0 5% 0 0;
}
div.cols3 div.column {
width: 29.8%;
padding: 0 5% 0 0;
}
div.cols4 div.column {
width: 21.1%;
padding: 0 5% 0 0;
}
div.cols5 div.column {
width: 15.9%;
padding: 0 5% 0 0;
}
div.columns div.collast {
padding: 0;
}
The thing that most people are forgetting is that when floating <li/> items, all of the items have to be the same height, or the columns start getting out of whack.
Since you're using a server side language, my recommendation would be to use CF to split the list into 3 arrays. Then you can use an outer ul to wrap the 3 inner ul like so:
<cfset thelist = "1,2,3,4,5,6,7,8,9,10,11,12,13">
<cfset container = []>
<cfset container[1] = []>
<cfset container[2] = []>
<cfset container[3] = []>
<cfloop list="#thelist#" index="i">
<cfif i mod 3 eq 0>
<cfset arrayappend(container[3], i)>
<cfelseif i mod 2 eq 0>
<cfset arrayappend(container[2], i)>
<cfelse>
<cfset arrayappend(container[1], i)>
</cfif>
</cfloop>
<style type="text/css">
ul li { float: left; }
ul li ul li { clear: left; }
</style>
<cfoutput>
<ul>
<cfloop from="1" to="3" index="a">
<li>
<ul>
<cfloop array="#container[a]#" index="i">
<li>#i#</li>
</cfloop>
</ul>
</li>
</cfloop>
</ul>
</cfoutput>
Using a modulo operation, you can quickly split your list into multiple lists by inserting a </ul><ul> during your loop.
<cfset numberOfColumns = 3 />
<cfset numberOfEntries = 34 />
<ul style="float:left;">
<cfloop from="1" to="#numberOfEntries#" index="i">
<li>#i#</li>
<cfif NOT i MOD ceiling(numberOfEntries / numberOfColumns)>
</ul>
<ul style="float:left;">
</cfif>
</cfloop>
</ul>
Use ceiling() instead of round() to ensure that you don't have extra values at the end of the list and that the last column is shortest.
Flexbox can be used to wrap items in both row and column directions.
The main idea is to set the flex-direction on the container to either row or column.
NB: Nowadays browser support is pretty good.
FIDDLE
(Sample markup taken from this old 'list apart' article)
ol {
display: flex;
flex-flow: column wrap; /* flex-direction: column */
height: 100px; /* need to specify height :-( */
}
ol ~ ol {
flex-flow: row wrap; /* flex-direction: row */
max-height: auto; /* override max-height of the column direction */
}
li {
width: 150px;
}
a {
display: inline-block;
padding-right: 35px;
}
<p>items in column direction</p>
<ol>
<li>Aloe
</li>
<li>Bergamot
</li>
<li>Calendula
</li>
<li>Damiana
</li>
<li>Elderflower
</li>
<li>Feverfew
</li>
<li>Ginger
</li>
<li>Hops
</li>
<li>Iris
</li>
<li>Juniper
</li>
<li>Kava kava
</li>
<li>Lavender
</li>
<li>Marjoram
</li>
<li>Nutmeg
</li>
<li>Oregano
</li>
<li>Pennyroyal
</li>
</ol>
<hr/>
<p>items in row direction</p>
<ol>
<li>Aloe
</li>
<li>Bergamot
</li>
<li>Calendula
</li>
<li>Damiana
</li>
<li>Elderflower
</li>
<li>Feverfew
</li>
<li>Ginger
</li>
<li>Hops
</li>
<li>Iris
</li>
<li>Juniper
</li>
<li>Kava kava
</li>
<li>Lavender
</li>
<li>Marjoram
</li>
<li>Nutmeg
</li>
<li>Oregano
</li>
<li>Pennyroyal
</li>
</ol>
To output the list into multiple grouped tag you can loop in this fashion.
<cfset list="1,2,3,4,5,6,7,8,9,10,11,12,13,14">
<cfset numberOfColumns = "3">
<cfoutput>
<cfloop from="1" to="#numberOfColumns#" index="col">
<ul>
<cfloop from="#col#" to="#listLen(list)#" index="i" step="#numberOfColumns#">
<li>#listGetAt(list,i)#</li>
</cfloop>
</ul>
</cfloop>
</cfoutput>
Here is another solution that allows for columned lists in the following style:
1. 4. 7. 10.
2. 5. 8. 11.
3. 6. 9. 12.
(but it's pure javascript, and requires jQuery, with no fallback)
The following contains a some code that modifies the Array prototype to give a new function called 'chunk' that breaks any given Array into chunks of a given size. Next is a function called 'buildColumns' that takes a UL selector string and a number used to designate how many rows your columns may contain. (Here is a working JSFiddle)
$(document).ready(function(){
Array.prototype.chunk = function(chunk_size){
var array = this,
new_array = [],
chunk_size = chunk_size,
i,
length;
for(i = 0, length = array.length; i < length; i += chunk_size){
new_array.push(array.slice(i, i + chunk_size));
}
return new_array;
}
function buildColumns(list, row_limit) {
var list_items = $(list).find('li').map(function(){return this;}).get(),
row_limit = row_limit,
columnized_list_items = list_items.chunk(row_limit);
$(columnized_list_items).each(function(i){
if (i != 0){
var item_width = $(this).outerWidth(),
item_height = $(this).outerHeight(),
top_margin = -((item_height * row_limit) + (parseInt($(this).css('margin-top')) * row_limit)),
left_margin = (item_width * i) + (parseInt($(this).css('margin-left')) * (i + 1));
$(this[0]).css('margin-top', top_margin);
$(this).css('margin-left', left_margin);
}
});
}
buildColumns('ul#some_list', 5);
});
Since I had the same problem and couldn't find anything "clean" I thought I'd posted my solution. In this example I use a reversed while loop so I can use splice instead of slice. The advantage now is splice() only needs an index and a range where slice() needs an index and the total. The latter tends to become difficult while looping.
Disadvantage is I need to reverse the stack while appending.
Example:
cols = 4;
liCount = 35
for loop with slice = [0, 9]; [9, 18]; [18, 27]; [27, 35]
reversed while with splice = [27, 8]; [18, 9]; [9, 9]; [0, 9]
Code:
// #param (list): a jquery ul object
// #param (cols): amount of requested columns
function multiColumn (list, cols) {
var children = list.children(),
target = list.parent(),
liCount = children.length,
newUl = $("<ul />").addClass(list.prop("class")),
newItems,
avg = Math.floor(liCount / cols),
rest = liCount % cols,
take,
stack = [];
while (cols--) {
take = rest > cols ? (avg + 1) : avg;
liCount -= take;
newItems = children.splice(liCount, take);
stack.push(newUl.clone().append(newItems));
}
target.append(stack.reverse());
list.remove();
}
You can try this to convert in cols.
CSS:
ul.col {
width:50%;
float:left;
}
div.clr {
clear:both;
}
Html Part :
<ul class="col">
<li>Number 1</li>
<li>Number 2</li>
<li>Number 19</li>
<li>Number 20</li>
</ul>
<ul class="col">
<li>Number 21</li>
<li>Number 22</li>
<li>Number 39</li>
<li>Number 40</li>
</ul>