I wrote this basic website, but the transition between the tabs from the browser of the phone seems sluggish. (On the other hand, the same page works good enough on my desktop).
What can I do in order to improve this?
Script:
function showPanel(panelIndex, colorCode) {
tabButtons.forEach(function (node) {
node.style.backgroundColor = "";
node.style.color = "";
});
tabButtons[panelIndex].style.backgroundColor = colorCode;
tabButtons[panelIndex].style.color = "white";
tabPanels.forEach(function (node) {
node.style.display = "none";
});
tabPanels[panelIndex].style.display = "block";
tabPanels[panelIndex].style.backgroundColor = colorCode;
}
Rather than looping two times, you can refactor your code to save the current button instance. Two forEach is too much code.
var tabButtons = document.querySelectorAll(".tabContainer .buttonContainer button");
var tabPanels = document.querySelectorAll(".tabContainer .tabPanel");
var lastPanel, lastButton;
function showPanel(currentButton, colorCode, panelIndex) {
if (lastButton) {
lastButton.style.backgroundColor = "";
lastButton.style.color = "";
}
lastButton = currentButton;
lastButton.style.backgroundColor = colorCode;
lastButton.style.color = "white";
if (lastPanel) {
lastPanel.style.display = "none";
}
lastPanel = tabPanels[panelIndex];
lastPanel.style.display = "block";
lastPanel.style.backgroundColor = colorCode;
}
showPanel(tabButtons[0], 'red', 0);
.title {
font-family: sans-serif;
color: blueviolet;
text-align: center;
}
.tabContainer {
width: 100%;
height: 350px;
}
.tabContainer .buttonContainer {
height: 15%;
}
.tabContainer .buttonContainer button {
width: 33.33%;
height: 100%;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 10px;
font-family: sans-serif;
font-size: 15px;
background-color: bisque;
}
.tabContainer .buttonContainer button:hover {
background-color: rosybrown;
}
.tabContainer .tabPanel {
height: 85%;
background-color: aquamarine;
color: black;
text-align: center;
padding-top: 10px;
padding-bottom: 10px;
box-sizing: border-box;
font-family: sans-serif;
font-size: 22px;
display: none;
}
.dataContainer {
font-size: 40px;
height: 85%;
width: 100%;
text-align: center;
background: Silver;
box-sizing: border-box;
font-family: sans-serif;
grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
grid-template-rows: 1fr 1fr 1fr;
grid-gap: 10px;
}
.calculateHFOV .input {
margin: 10px;
padding: 10px;
background: LightSkyBlue;
}
.calculateFocalLength .input {
margin: 10px;
padding: 10px;
background: lemonchiffon;
}
.fov {
padding: 10px;
margin: 10px;
background: LightSalmon;
}
.natoTarget {
margin: 10px;
padding: 10px;
background: PaleTurquoise;
}
.humanTarget {
margin: 10px;
padding: 10px;
background: LightPink;
}
.objectTarget {
margin: 10px;
padding: 10px;
background: PaleGreen;
}
.settings .parameters {
margin: 10px;
padding: 10px;
background: PaleTurquoise;
}
.settings .linePairs {
margin: 10px;
padding: 10px;
background: LightPink;
}
.settings .targetSize {
margin: 10px;
padding: 10px;
background: PaleGreen;
}
<div class="tabContainer">
<div class="buttonContainer">
<button onclick="showPanel(this,'red', 0)" style="">Calculate HFOV</button>
<button onclick="showPanel(this,'green', 1)" style="">Calculate Focal Length</button>
<button onclick="showPanel(this,'yellow', 2)">Settings</button>
</div>
<div class="tabPanel" style="display: none; background-color: red;">
<div class="calculateHFOV">
<div class="dataContainer">
<div class="input">input</div>
<div class="fov">fov</div>
<div class="natoTarget">natoTarget</div>
<div class="humanTarget">humanTarget</div>
<div class="objectTarget">objectTarget</div>
</div>
</div>
</div>
<div class="tabPanel" style="display: none; background-color: green;">
<div class="calculateFocalLength">
<div class="dataContainer">
<div class="input">input</div>
<div class="fov">fov</div>
<div class="natoTarget">natoTarget</div>
<div class="humanTarget">humanTarget</div>
<div class="objectTarget">objectTarget</div>
</div>
</div>
</div>
<div class="tabPanel" style="display: block; background-color: yellow;">
<div class="settings">
<div class="dataContainer">
<div class="parameters">parameters</div>
<div class="linePairs">linePairs</div>
<div class="targetSize">targetSize</div>
</div>
</div>
</div>
</div>
Related
I'm trying to append the picture that inserted, so it can be viewed.
So here the code where i can input or insert the picture :
<style>
body {
height: 100%;
padding: 0;
margin: 0;
background-color: white;
max-width: 1920px;
}
.main-container {
display: flex;
min-height: 100vh;
align-items: center;
justify-content: center;
background-image: url('/img/');
background-repeat: no-repeat;
background-attachment: fixed;
background-size: 100% 100%;
}
.listing-container {
width: 60%;
padding: 30px;
margin: auto;
border-radius: 35px;
box-shadow: 0px 0px 7px #00000029;
background-color: white;
}
.input-credential {
color: #3C58A7;
}
.form-label {
margin-left: 15px;
font-size: 25px;
font-family: Montserrat-Bold;
}
.question-mark {
color: #3C58A7;
}
.question-mark:hover {
cursor: pointer;
}
.form-control {
font-family: Montserrat-Regular;
}
.input-border {
padding-bottom: 15px;
padding-top: 15px;
border-radius: 25px;
box-shadow: 0px 0px 5px #00000029;
}
.error-message {
font-size: 16px;
color: red;
padding: 15px 12px;
font-family: Montserrat-Regular;
}
.input-gambar {
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
#input-gambar-text {
padding-left: 42.5%;
color: #3C58A7;
}
#input-gambar-text:hover {
color: rgb(103, 99, 99);
}
.grid {
margin-top: 50px;
display: flex;
justify-content: space-around;
flex-wrap: wrap;
gap: 20px;
}
.grid .form-element {
width: 200px;
height: 200px;
box-shadow: 0px 0px 20px 5px rgba(100, 100, 100, 0.1);
}
.grid .form-element input {
display: none;
}
.grid .form-element img {
width: 200px;
height: 200px;
}
.grid .form-element div {
position: relative;
height: 40px;
margin-top: -40px;
background: rgba(0, 0, 0, 0.5);
text-align: center;
line-height: 40px;
font-size: 13px;
color: #f5f5f5;
font-weight: 600;
}
.grid .form-element div span {
font-size: 40px;
}
#tombol-cancel-gambar {
margin: auto;
padding-top: 15px;
padding-bottom: 15px;
padding-left: 15px;
padding-right: 25px;
color: white;
font-size: 25px;
background-color: #3C58A7;
border-radius: 45px;
border-color: #3C58A7;
font-family: Montserrat-Bold;
align-items: center;
display: flex;
}
#tombol-cancel-gambar:hover {
color: #3C58A7;
background-color: white;
border-color: #3C58A7;
}
</style>
<body>
<div class="main-container">
<div class="listing-container">
<div class="row">
<div class="col-lg-12">
<div class="mb-3 input-credential">
<label class="form-label" for="myfile">
Masukkan Gambar
<span class="question-mark" data-toggle="tooltip" data-placement="bottom" title="Masukkan gambar produk anda">
<i class="fas fa-question-circle"></i>
</span>
</label>
<div class="grid" id="preview_test1">
<div class="form-element" id="test1">
<input type="file" id="file-1" accept="image/*" multiple>
<label for="file-1" id="file-1-preview">
<img src="/img/insert_gambar_penambahan_listing_barang.jpg" alt="" id="size-preview-image">
<div>
<span>+</span>
</div>
</label>
</div>
</div>
<div id="preview_test2">
</div>
</div>
</div>
</div>
</div>
</div>
</body>
And this is the function that i used to show multiple picture that i inserted :
function cancel_form_data_gambar() {
$("#preview_test1").empty();
$("#preview_test2").empty();
$("#preview_test1").append('<div class="form-element" id="test1"></div>');
$("#test1").append('<input type="file" id="file-1" accept="image/*" multiple>');
$("#test1").append('<label for="file-1" id="file-1-preview"></label>');
$("#file-1-preview").append('<img src="/img/insert_gambar_penambahan_listing_barang.jpg" alt="" id="size-preview-image">');
$("#file-1-preview").append('<div> <span>+</span> </div>');
}
function readURL(input) {
$("#preview_test1").empty();
for (var i = 0; i < input.length; i++) {
$("#preview_test2").append('<img id="test_gambar' + i + '"src="#">');
}
for (var i = 0; i < input.length; i++) {
if (input.files && input.files[i]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#test_gambar' + i + '').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[i]);
}
}
$('#preview_test2').append('<button type="button" id="tombol-cancel-gambar" onclick="cancel_form_data_gambar()" class="btn btn-primary listing-button">Cancel Gambar</button>');
}
$("#file-1").change(function() {
readURL(this);
});
the picture is suppose to be showed in id="#preview_test2" after the picture was inserted. But the picture won't appear in id="#preview_test2" and only the button appear in there. So, how can i solve it?
At first there were 4 buttons I only wanted 3 so I removed the 4th one and that's why I want to make the remaining 3 look horizontally centered, it looks weird because of the 4th button's blank space. I tried a few things but they didn't work out.
var tabButtons = document.querySelectorAll(".tabContainer .buttonContainer button");
var tabPanels = document.querySelectorAll(".tabContainer .tabPanel");
function showPanel(panelIndex, colorCode) {
tabButtons.forEach(function(node) {
node.style.backgroundColor = "";
node.style.color = "";
});
tabButtons[panelIndex].style.backgroundColor = colorCode;
tabButtons[panelIndex].style.color = "white";
tabPanels.forEach(function(node) {
node.style.display = "none";
});
tabPanels[panelIndex].style.display = "block";
tabPanels[panelIndex].style.backgroundColor = colorCode;
}
showPanel(0, '#f44336');
.title {
color: #dc2d5e;
text-align: center;
}
.tabContainer {
width: 100%;
height: 350px;
}
.tabContainer .buttonContainer {
height: 15%;
align-items: center;
align-content: center;
justify-content: center;
text-align: center;
}
.tabContainer .buttonContainer button {
width: 25%;
height: 100%;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 10px;
font-family: sans-serif;
font-size: 18px;
background-color: #eee;
}
.tabContainer .buttonContainer button:hover {
background-color: #d7d4d4;
}
.tabContainer .tabPanel {
height: 85%;
background-color: gray;
color: white;
text-align: center;
padding-top: 105px;
box-sizing: border-box;
font-family: sans-serif;
font-size: 22px;
display: none;
}
<h1 class="title">Recieved Data</h1>
<div class="tabContainer">
<div class="buttonContainer">
<button onclick="showPanel(0,'#f44336')">Feedbacks</button>
<button onclick="showPanel(1,'#4caf50')">Suggestions</button>
<button onclick="showPanel(2,'#2196f3')">Messages</button>
</div>
<div class="tabPanel">Tab 1:Content</div>
<div class="tabPanel">Tab 2:Content</div>
<div class="tabPanel">Tab 3:Content</div>
</div>
You are really close, adding these two flex properties can obtain the desired solution:
.tabContainer .buttonContainer{
display: flex;
justify-content: space-between;
}
.title{
color: #dc2d5e;
text-align: center;
}
.tabContainer{
width: 100%;
height: 350px;
}
.tabContainer .buttonContainer{
display: flex;
height: 15%;
align-items: center;
align-content: center;
justify-content: space-between;
text-align: center;
}
.tabContainer .buttonContainer button{
width: 25%;
height: 100%;
float: left;
border: none;
outline:none;
cursor: pointer;
padding: 10px;
font-family: sans-serif;
font-size: 18px;
background-color: #eee;
}
.tabContainer .buttonContainer button:hover{
background-color: #d7d4d4;
}
.tabContainer .tabPanel{
height: 85%;
background-color: gray;
color: white;
text-align: center;
padding-top: 105px;
box-sizing: border-box;
font-family: sans-serif;
font-size: 22px;
display: none;
}
<h1 class="title">Recieved Data</h1>
<div class="tabContainer">
<div class="buttonContainer">
<button onclick="showPanel(0,'#f44336')">Feedbacks</button>
<button onclick="showPanel(1,'#4caf50')">Suggestions</button>
<button onclick="showPanel(2,'#2196f3')">Messages</button>
</div>
<div class="tabPanel">Tab 1:Content</div>
<div class="tabPanel">Tab 2:Content</div>
<div class="tabPanel">Tab 3:Content</div>
</div>
This flexbox guide is my go-to any time I run into this type of issue!
You just need to add this to your css !
.buttonContainer{
display: flex;
}
Since there are only 3 buttons now, I would just make each one's width a third.
You can accomplish this by doing:
.tabContainer .buttonContainer button{
width: calc(100% / 3);
}
EDIT: So it would look like this:
var tabButtons = document.querySelectorAll(".tabContainer .buttonContainer button");
var tabPanels = document.querySelectorAll(".tabContainer .tabPanel");
function showPanel(panelIndex, colorCode) {
tabButtons.forEach(function(node) {
node.style.backgroundColor = "";
node.style.color = "";
});
tabButtons[panelIndex].style.backgroundColor = colorCode;
tabButtons[panelIndex].style.color = "white";
tabPanels.forEach(function(node) {
node.style.display = "none";
});
tabPanels[panelIndex].style.display = "block";
tabPanels[panelIndex].style.backgroundColor = colorCode;
}
showPanel(0, '#f44336');
.title {
color: #dc2d5e;
text-align: center;
}
.tabContainer {
width: 100%;
height: 350px;
}
.tabContainer .buttonContainer {
height: 15%;
align-items: center;
align-content: center;
justify-content: center;
text-align: center;
}
.tabContainer .buttonContainer button {
width: calc(100% / 3);
height: 100%;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 10px;
font-family: sans-serif;
font-size: 18px;
background-color: #eee;
}
.tabContainer .buttonContainer button:hover {
background-color: #d7d4d4;
}
.tabContainer .tabPanel {
height: 85%;
background-color: gray;
color: white;
text-align: center;
padding-top: 105px;
box-sizing: border-box;
font-family: sans-serif;
font-size: 22px;
display: none;
}
<h1 class="title">Recieved Data</h1>
<div class="tabContainer">
<div class="buttonContainer">
<button onclick="showPanel(0,'#f44336')">Feedbacks</button>
<button onclick="showPanel(1,'#4caf50')">Suggestions</button>
<button onclick="showPanel(2,'#2196f3')">Messages</button>
</div>
<div class="tabPanel">Tab 1:Content</div>
<div class="tabPanel">Tab 2:Content</div>
<div class="tabPanel">Tab 3:Content</div>
</div>
calc() is widely supported on modern browsers.
I m making some project.
When I click "number1" button, I thought "number2" and "drag-zone" box is removed at once
But It's not happened. I have to click "number1" to three time to remove "the number2" and "drag-zone"
I want to remove that at once. What's my problem in my code?
I don't know How could I remove NodeList at once
let list = document.getElementsByClassName("boxDrop");
function remove(num) {
if (num === 0) {
for (let i = 0; i < list[1].childNodes.length; i++)
list[1].removeChild(list[1].childNodes[i]);
}
}
* {
align-items: center;
text-align: center;
justify-content: space-evenly;
}
button {
border: none;
background-color: transparent;
font-size: 20px;
border-radius: 10px;
}
button:hover {
background-color: rgb(252, 211, 77);
}
.thumbDropBox {
display: flex;
border: 3px solid rgb(209, 178, 2);
padding: 15px;
margin-top: 100px;
cursor: pointer;
}
.drop-zone {
display: flex;
border: 3px dashed rgb(253, 196, 39);
margin: 10px;
width: 200px;
height: 200px;
padding: 20px;
font-size: 30px;
font-weight: bold;
border-radius: 14px;
}
.drop-zone__over {
border-style: solid;
}
.drop-zone__input {
display: none;
}
.drop-zone__thumb {
background-color: rgb(235, 235, 235);
height: 100%;
width: 100%;
border-radius: 15px;
overflow: hidden;
position: relative;
}
.drop-zone__thumb::after {
content: attr(data-label);
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
background-color: rgb(192, 192, 192);
position: absolute;
bottom: 0;
}
.question {
display: inline-block;
padding: 20px;
font-size: 30px;
}
<div class="thumbDropBox">
<div class="boxDrop">
<div class="drop-zone">
<span class="drop-zone__prompt">Drag or Choose</span>
<input type="file" class="drop-zone__input">
<!-- <div class="drop-zone__thumb" data-label="eskdflsdf.txt"></div> -->
</div>
<button onclick="remove(0)">Number1</button>
</div>
<div class="boxDrop">
<div class="drop-zone">
<span class="drop-zone__prompt">Drag or Choose</span>
<input type="file" class="drop-zone__input">
<!-- <div class="drop-zone__thumb" data-label="eskdflsdf.txt"></div> -->
</div>
<button onclick="remove(1)">Number2</button>
</div>
</div>
<span class="question">Whose is the Better?</span>
Guys need some help im trying to figure out how can i execute multiple events on single click i am able to change the image on my gallery but i wanted to add some text label on each Img click i need to change each H3 and replace whenever i click the other image, i need to do a multiple event on single click
const current = document.querySelector('#current');
const imgs = document.querySelectorAll('.imgs img');
const main = document.querySelector('#main-info h3');
const info = document.querySelector('.info');
imgs.forEach(img => img.addEventListener('click', imgClick));
function imgClick(e) {
current.src = e.target.src;
}
body {
font-family: Arial, Helvetica, sans-serif;
font: 15px/1.5;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.container {
width: 90%;
margin: auto;
overflow: hidden;
}
header {
display: flex;
justify-content: space-between;
padding-top: 5px;
background-color: #567890;
min-height: 130px;
border-bottom: 3px #e0480c solid;
padding: 0 20px 0 0;
}
header #branding {
float: left;
margin: 0;
}
header #branding img {
margin: 0;
padding: 0;
}
header ul {
margin: 0;
padding: 0;
}
header li {
display: inline;
float: left;
padding: 0 20px 0 20px;
margin-top: 50px;
}
header a {
text-decoration: none;
color: #ffffff;
text-transform: uppercase;
font-size: 16px;
}
header a:hover {
color: #b9b8b9;
opacity: 1;
}
header nav {
float: right;
padding-bottom: 50px;
}
.current a {
color: #e0480c;
font-weight: bold;
}
#showcase {
min-height: 400px;
background: linear-gradient(rgba(0, 0, 50, 0.5), rgba(0, 0, 50, 0.5)),
url(/img/enseymada.jpg) no-repeat 0 -400px;
text-align: center;
background-size: cover;
opacity: 0.9;
}
#showcase .main-info {
margin-top: 100px;
margin-bottom: 10px;
justify-content: center;
font-size: 50px;
font-weight: 600;
color: #fffcff;
}
#showcase p {
font-size: 20px;
font-weight: 200;
color: #ccc;
}
.topinfo {
text-align: center;
justify-content: center;
}
.info2 {
text-align: center;
justify-content: center;
}
footer {
width: 100%;
bottom: 0;
position: relative;
}
.foot {
background: #e24305;
color: #fff;
height: 10px;
margin: 0;
width: 100%;
text-align: center;
padding: 7px 10px;
justify-content: center;
align-items: center;
}
.main-img img,
.imgs img {
margin: auto;
width: 100%;
background: cover;
border-radius: 10%;
}
.imgs {
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 5px;
background: cover;
cursor: pointer;
}
.wrapper {
border: #444 solid 3px;
max-width: 800px;
margin: auto;
height: 100%;
padding: 5px;
align-items: center;
justify-content: center;
overflow: hidden;
}
.newsletter {
margin-bottom: 100px;
padding: 0;
width: 100%;
height: 80px;
align-items: center;
justify-content: center;
background-color: #567890;
}
.newsletter h1 {
float: left;
color: #ffffff;
}
.newsletter .btn {
display: inline;
margin: 20px 5px;
padding: 10px;
background-color: #444;
color: #fff;
border: none;
}
.newsletter #subscribe {
padding: 10px;
margin-left: 10px;
border: none;
}
<div class="wrapper">
<div class="main-img">
<h3 id="main-info">Classic Enseymada</h3>
<img src="img/image2.jpg" id="current">
</div>
<div class="imgs">
<img src="img/image2.jpg">
<div class="info">
<img src="img/image3.jpg">
<h3>Nuttela</h3>
</div>
<img src="img/image4.jpg">
<img src="img/image6.jpg">
<img src="img/image7.jpg">
<img src="img/image8.jpg">
</div>
</div>
<footer><div class="foot">Copyright © Abby Cook's 2020</div></footer>
<script src="./js/main.js"></script>
</body>
</html>
I am assuming that you want to pass more arguments to your imgClick function.
One way to do it is to use anonymous functions, something like this should do the trick :
imgs.forEach(img => img.addEventListener('click', function(e){
imgClick(e, 'param1', 'param2',);
}));
function imgClick(e, param1, param2,) {
current.src = e.target.src;
// your code
}
Add then your code in the function.
I have the following code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>StackOverflow Question</title>
<style>
.container--wrap {
background-color: #000000;
border-radius: 15px;
margin: 5px;
overflow: hidden;
justify-content: stretch;
align-items: flex-end;
}
.scroller2{
height: 250px;
overflow-y: scroll;
}
.circle {
position: relative;
margin-bottom: 40px;
height: 20px;
display: flex;
align-items: center;
}
.circle::before {
content:"";
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 5px;
}
.circle::after {
position: absolute;
content: '';
left: 7.5px;
top: 20px;
width: 5px;
background: #4d4d4d;
height: 40px;
}
.minor::before {
background-color: purple;
}
.major::before {
background-color: red;
}
.gray::before {
background-color: gray;
}
.tlbtn {
background-color: #343434;
border-radius: 10px;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
font-family: robotobold;
}
#tltitle,.tlbtn{
display: inline-flex;
}
</style>
</head>
<body>
<script>
function btn1Click() {
document.getElementById("btn1").style.backgroundColor="#5c5c5c";
document.getElementById("btn2").style.backgroundColor="#343434";
}
function btn2Click() {
document.getElementById("btn2").style.backgroundColor="#5c5c5c";
document.getElementById("btn1").style.backgroundColor="#343434";
}
</script>
<div class="container--wrap-scroll scroller2" id="timeline">
<p id="tltitle" style="color: #D4E1E4; font-size: 20px; text-align: left; padding-top: 0px; padding-right: 10px;color: black;"><b>Timeline</b></p>
<div id="btn1" class="tlbtn" style="margin-bottom: -10px; background-color: #5c5c5c;" onclick="btn1Click();"><text style="font-size: 15px; font-family: robotobold;text-align: center;">Newest</text></div>
<div id="btn2" class="tlbtn" style="margin-bottom: -10px;" onclick="btn2Click();"><text style="font-size: 15px; font-family: robotobold; text-align: center;">Oldest</text></div>
<div class="circle major "><text style="color:red; font-family:robotolight; font-size: 12px;">Major Event | Yesterday</text></div>
<div class="circle gray"><text style="color:black; font-family:robotolight; font-size: 12px;">Information | 2 days ago</text></div>
<div class="circle gray"><text style="color:black; font-family:robotolight; font-size: 12px;">Information | 1 week ago</text></div>
<div class="circle minor"><text style="color:purple; font-family:robotolight; font-size: 12px;">Minor Event | 1 month ago</b></text></div>
</div>
</body>
</html>
When 'Oldest' is pressed, I would like the order of the div elements to reverse sort - please notice that the last circle has a line which goes below it, and I would like this to stay the same:
e.g. Major Event will be at the bottom when OLDEST is pressed and have a grey line below it as well.
Is there a way I can do this?
Screenshot:
If you want to use only CSS, you could try using Flexbox and switching between flex-direction column and column-reverse:
const timeline = document.getElementById('timeline');
const newestButton = document.getElementById('button--newest-first');
const oldestButton = document.getElementById('button--oldest-first');
newestButton.onclick = () => {
timeline.classList.remove('timeline--oldest-first');
timeline.classList.add('timeline--newest-first');
oldestButton.classList.remove('button--selected');
newestButton.classList.add('button--selected');
};
oldestButton.onclick = () => {
timeline.classList.add('timeline--oldest-first');
timeline.classList.remove('timeline--newest-first');
oldestButton.classList.add('button--selected');
newestButton.classList.remove('button--selected');
};
body {
margin: 0;
padding: 8px;
font-family: monospace;
font-size: 14px;
}
.header {
display: flex;
padding-bottom: 8px;
margin-bottom: 16px;
align-items: center;
border-bottom: 2px solid black;
}
.title {
margin-right: auto;
}
.button {
font-family: monospace;
font-size: 14px;
border-radius: 2px;
padding: 4px 8px;
margin-left: 8px;
cursor: pointer;
border: 0;
outline: none;
border: 2px solid black;
background: transparent;
}
.button--selected {
background: yellow;
}
.timeline {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
.timeline--newest-first {
flex-direction: column;
}
.timeline--oldest-first {
flex-direction: column-reverse;
}
.circle {
position: relative;
margin-bottom: 16px;
height: 20px;
display: flex;
align-items: center;
}
.timeline--newest-first > .circle:last-child,
.timeline--oldest-first > .circle:first-child {
margin-bottom: 0;
}
.circle::before {
content:"";
display: inline-block;
width: 16px;
height: 16px;
border-radius: 50%;
margin-right: 16px;
border: 2px solid black;
}
.circle::after {
position: absolute;
content: '';
left: 9px;
top: 20px;
width: 2px;
background: #000;
height: 16px;
}
.timeline--newest-first > .circle:last-child::after,
.timeline--oldest-first > .circle:first-child::after {
display: none;
}
.minor::before {
background-color: purple;
}
.major::before {
background-color: red;
}
.gray::before {
background-color: gray;
}
<header class="header">
<strong class="title">TIMELINE</strong>
<button id="button--newest-first" class="button button--selected">
NEWEST
</button>
<button id="button--oldest-first" class="button">
OLDEST
</button>
</header>
<ul class="timeline timeline--newest-first" id="timeline">
<li class="circle major ">
Major Event | Yesterday
</li>
<li class="circle gray">
Information | 2 days ago
</li>
<li class="circle gray">
Information | 1 week ago
</li>
<li class="circle minor">
Minor Event | 1 month ago
</li>
</ul>