Web Design/Layout toggle
This is a demonstration for toggling between two layouts using a script that toggles between the CSS class names "grid
" and "list
".
The HTML document used in the demo has the style sheet and script on board, embedded using <style>
and <script>
tags respectively. The appearance of the elements is determined through classes in the style sheet. The items' descriptions are hidden in grid view. The source code is annotated with comments.
This demonstration also makes use of tooltips using the title
attribute, showing additional details when the pointer is hovered on some of the elements.
When the user toggles between the list and grid views, the text in the button is changed accordingly. The script memorizes the last used view by storing it into a browser cookie, and loads it when opened the next time. The Firefox browser stores cookies for local HTML files (file:///
), as has been successfully tested. A localhost server might be necessary to test this feature on a different browser.
At the end of the script, the one list item is multiplied between 10 to 50 times and sets a random background colour for variety. This would not be done on an actual website, and serves for illustration in this demo.
Source code
edit<!DOCTYPE html>
<html lang="en">
<head>
<title>Grid and list layout toggle demo</title>
<meta name="author" content="Elominius from Wikiversity">
<!-- necessary to render the interpuncts correctly in older browser versions -->
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<!-- compatibility -->
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<button class="toggle_grid_list_button" id="toggle_grid_list_button" onclick="toggleView_demo();">Toggle to grid view</button>
<!-- changed to "Toggle to list view" and back by the script when pressed -->
<ul class="item_container grid">
<li>
<div class="thumbnail_wrapper">
<div class="thumbnail_container">
<!-- a picture would go here -->
<span class="thumbnail_duration">6:38</span>
</div>
</div>
<div class="info_wrapper">
<div class="title_container" title="This is a title.">
<!-- fake hyperlink colour for illustration purposes -->
<span class=fake_URL>This is a title.</span>
</div>
<div class="status_container">
<!-- non-breaking spaces after numbers -->
by <span class="channel_name fake_URL" title="312,147 subscribers">VideoCreator</span> <span class="subscriber_count list_show">(312,147 subscribers)</span> • <time class="upload_date" datetime="2022-06-12T10:11:16" title="June 12, 2022 10:11:16 (UTC)">2 weeks ago</time> • <span class="view_count" title="56,887 views since 24 hours">1,013,237 views</span> • <span class="rating" title="106,228 likes, 3187 dislikes">97% liked</span>
</div>
<div class="tag_container list_show">
<span class="video_tag">This is a tag.</span>
<span class="video_tag">example</span>
<span class="video_tag">demo</span>
</div>
<div class="description_container list_show">
This is the description. It can only be seen in list view. It does not matter if it contains too much text for the space, since excess text can be hidden or extend downwards.
</div>
</div>
</li>
</ul>
<!-- This "type" attribute serves as a label for the source code, and is not necessary in modern browsers. Same with "text/javascript". -->
<style type="text/css">
/* font pack */
body { font-family: 'noto sans', ubuntu, 'segoe ui', futura, arial, helvetica, 'trebuchet ms', tahoma, verdana, sans-serif; }
/* shared style */
.item_container {
list-style: none;
padding-right: 1em;
}
.thumbnail_container {
width:256px; height:144px;
position: relative; /* necessary to keep .thumbnail_duration inside thumbnail */
border: 2px solid grey;
margin-right: 1em;
margin-bottom: 0.5em;
background-color: lightblue; /* placeholder */
border-radius: 5px;
}
/* title and status */
.title_container { font-size:20pt; }
.fake_URL { color:#48C; } /* for illustration */
.status_container { font-size:10pt; color:#555; }
/* tags */
.tag_container { color:grey; font-size:small; }
.video_tag { border:1px solid #38F; border-radius:10px; padding:0 0.5em; }
.video_tag:hover { color: #ddd; }
/* description */
.description_container {
display:block;
/* description height limit */
max-height:5em; /* 5 lines */
overflow-y: hidden; /* hide excess text */
/* end line with ellipsis for newer browsers */
/* display: -webkit-box;
text-overflow:ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5; */
}
.thumbnail_duration {
display: inline-block;
position: absolute;
background-color: rgba(0,0,0,0.5);
padding:0 4px;
bottom:0; right:0;
border-radius: 5px; /* fallback */
border-radius: 5px 0 3px 0;
}
/* only visible in specific modes */
.grid_show { display: none; }
.list_show { display: none; }
/* grid view */
.item_container.grid .grid_show { display: inline; }
/* moves title closer to video above than below to clarify that it belongs to the former */
.item_container.grid .status_container { padding-bottom: 15pt; }
.item_container.grid .thumbnail_container { margin-bottom: 0; }
.item_container.grid li {
/* limit width per item */
display: inline-block;
width: 256px;
margin-right:1em;
}
/* hide description – obsolete due to .list_show */
/* .item_container.grid .description_container { display:none; } */
/* list view */
.item_container.list .list_show { display: inline; }
.item_container.list .description_container {
display:block;
width:calc(100% - 300px); /* limit width to avoid breaking underneath */
}
.item_container.list li { display:block; clear:both; } /* extend over entire row */
.item_container.list .thumbnail_wrapper {
display: inline-block;
width: 256px;
float:left;
margin-right: 1em;
}
.item_container.list .info_wrapper {
/* Deactivated due to possibility of it getting below the thumbnail. Might be necessary on older browsers, but would require fixed width. */
/* display: inline-block; */
/* width: 256px; */
}
/* responsive width - puts information below thumbnail on narrow displays (optional) */
@media (max-width: 720px) {
.item_container.list .thumbnail_wrapper { float:none; }
.item_container.list .description_container { width: 100%; }
}
/* dark theme (optional) */
body { background-color:#222; color:#eee; }
.status_container { color:#aaa; }
</style>
<script type="text/javascript">
// put item container into shortcut variable
var item_container = document.getElementsByClassName("item_container")[0];
var first_item = item_container.getElementsByTagName("li")[0];
var toggle_grid_list_button = document.querySelectorAll(".toggle_grid_list_button")[0];
// set view
function setView(mode) {
// if none set, default to grid
if (item_container.className.search("grid")+item_container.className.search("list") == -2) {
item_container.className="item_container grid";
document.cookie = "view_mode=grid";
}
switch(mode) {
case "list":
// replaces the "grid" class with "list"
item_container.className = item_container.className.replace('grid','list');
// changes button label
toggle_grid_list_button.innerHTML="Toggle to grid view";
// stores view mode into cookie
document.cookie = "view_mode=list";
break;
case "grid":
// replaces the "list" class with "grid"
item_container.className = item_container.className.replace('list','grid');
// changes button label
toggle_grid_list_button.innerHTML="Toggle to list view";
// stores view mode into cookie
document.cookie = "view_mode=grid";
break;
}
}
// toggle view
function toggleView_demo(mode) {
if (
// checks if grid mode is activated by looking for the word "grid" in the class
item_container.className.search("grid") > -1
) {
setView("list");
} else if (
// checks for list mode
item_container.className.search("list") > -1
) {
setView("grid");
} else {
// add "grid" class by default
item_container.className+=" grid";
document.cookie = "view_mode=grid";
}
}
// Cookie function dependencies
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
var expires = "expires="+d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
// check configuration (note: only Firefox stores cookies for locally opened HTML files.)
if ( getCookie("view_mode") == "grid" ) setView("grid");
if ( getCookie("view_mode") == "list" ) setView("list");
// Description width fallback for older browsers – uncomment and optionally convert to "onresize" if necessary.
/*
document.body.appendChild( document.createElement("style") );
var description_width_fallback = document.body.lastChild;
document.body.lastChild.className="description_width_fallback"; // label for page inspector
window.addEventListener('resize', function(event) {
if ( item_container.className.search("list") > -1 ) {
description_width_fallback.innerHTML = ".item_container.list .description_container { width: " + (first_item.offsetWidth-400) +"px; }";
}
}, true);
*/
// Multiply list items for illustrative purposes – the following code would not be implemented on an actual web site.
var li_1_content = first_item.innerHTML;
var color_list = ['darkred', 'green', 'blue', 'yellow', 'orange', 'darkorange', 'darkgreen', 'darkseagreen', 'lightyellow', 'lightblue', 'lightskyblue', 'lightgreen', 'teal', 'turquoise', 'darkturquoise', 'mediumturquoise', 'lightcoral', 'antiquewhite', 'aqua', 'aquamarine', 'purple', 'violet', 'darkviolet', 'indigo', '#38F', 'lightseagreen', 'deepskyblue', 'steelblue', 'royalblue', 'beige', 'ivory', 'gray', 'slategray', 'darkslategray', 'wheat', 'gold', 'silver', 'brown', 'olive', 'lime', 'limegreen', 'greenyellow', 'yellowgreen', 'seagreen', 'crimson'];
var count = 0;
for (
count = 0; // start counter
count < Math.floor(10+Math.random()*40); // repeat 10 to 50 times
count++ // count up
) {
item_container.appendChild( document.createElement("li") );
item_container.lastChild.innerHTML=li_1_content;
// random color
var random_number = Math.floor(Math.random()*(color_list.length));
item_container.lastChild.querySelector(".thumbnail_container").style.backgroundColor=color_list[random_number];
}
</script>
</body>
</html>