Building CSS Grid with N columns, 2 rows, max height of container - razor

New to Grid in CSS and, of course, starting with a more convoluted need.
Think an airport Arrivals/Departures display. No keyboard, no mouse, no human interaction. This callout app used to be just one big long scrolling list. I am turning it into a little more organized layout. Depending on what screen it finally shows up on it may have room for 2 columns, 3 columns maybe even 5 columns - where each column is the same width and there is a minimum width.
1st row: header / full width / 3 lines of text
2nd row: should be equal to the remaining height, full width and is a container
In the container:
2 rows (title row, contents row)
N columns (where column has min-width) --> also a view panel for text in a marquee (vert
scrolling via js)
#model wsGT4.Models.DictionaryResultSet<string, List<wsGT4.Models.Callout>>
#{
ViewBag.Title = "Callout";
Layout = "~/Views/Shared/_EmptyLayout.cshtml";
}
<section class="header">
<H1>TOMORROW'S CALLOUTS WILL DISPLAY STARTING AT 5PM</H1>
<H2>BRING DOCS TO CALLOUTS</H2>
#if (Model.Success == false)
{
foreach (var msg in Model.Messages)
{
<h2>#msg</h2>
}
}
else
{
if (DateTime.Now.AddHours(Model.TimezoneOffset).Hour >= 17)
{
<h2>CALLOUTS FOR <span style="color:red; background-color: yellow;">TOMORROW</span> - #DateTime.Now.AddDays(1).ToString("MMM dd") <span style="font-size:.6em">(#DateTime.Now.AddHours(Model.TimezoneOffset).ToString("HH:mm"))</span></h2>
}
else
{
<h2>CALLOUTS FOR TODAY - #DateTime.Now.ToString("MMM dd") <span style="font-size:.6em">(#DateTime.Now.AddHours(Model.TimezoneOffset).ToString("HH:mm"))</span></h2>
}
}
</section>
<section class="container">
#foreach (var kvp in Model.ResultList.OrderBy(a => a.Key))
{
<div class="timeDisplay">
>>> #kvp.Key
</div>
<div class="viewPort">
<div class="textList">
#foreach (var subject in kvp.Value.OrderBy(a => a.LastName).ThenBy(a => a.SubjectId))
{
<span>#subject.LastName</span>
<span>##subject.SubjectId</span>
<span>#subject.EventTitle</span>
}
</div>
</div>
}
</section>
CSS (which I am royally screwing up)
.header {
padding: 5px;
border: groove;
border-bottom-color: black;
border-width: 2px;
/* Grid styles */
display: grid;
align-items: center;
/*grid-template-columns: 1fr;*/
grid-template-rows: repeat(3, 1fr);
}
.container {
max-height: 100vh;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 30px auto-fill;
grid-gap: 5px;
}
.timeDisplay{
max-height: 30px;
}
.viewPort {
height: 100%;
overflow: hidden;
}
.textList {
height: 100%;
font-size: 125%;
display: grid;
grid-template-columns: 3fr 2fr 5fr;
}
Since the model collection coming back can have an unknown number of time/list sets I am trying to let automation do some of the work. The idea being that if I have more columns than what can fit then they are either (A) not displayed or (B) wrap below the bottom of the screen, effectively being hidden.

So I changed my approach a little bit after diving into flex vs grid in CSS. The container got rewritten this way:
<section class="wrapper">
<ul class="colList">
#foreach (var kvp in Model.ResultList.OrderBy(a => a.Key))
{
<li class="columnItem">
<div class="columnTitle--wrapper">
<h2>>>> #kvp.Key</h2>
</div>
<div class="cardViewer">
<div class="cardList">
<ul class="cardList--ul">
#foreach (var subject in kvp.Value.OrderBy(a => a.EventTitle).ThenBy(a => a.LastName).ThenBy(a => a.SubjectId))
{
<li class="cardItem">
<h3>#subject.EventTitle.ToUpper()</h3>
<h3>#subject.LastName.ToUpper()</h3>
<h3>##subject.SubjectId.ToUpper()</h3>
</li>
}
</ul>
</div>
</div>
</li>
}
</ul>
</section>
and the CSS turned into:
/* column styles */
.wrapper {
}
.colList {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
grid-gap: .5rem;
align-items: start;
top: 500vh;
}
.columnItem {
border-radius: .2rem;
padding: .5rem;
}
.columnTitle--wrapper {
}
.columnTitle--wrapper h2 {
font-weight: 700;
}
/* card styles */
.cardViewer {
overflow: hidden;
height: 80vh;
max-height: 80vh;
}
.cardList {
position: relative;
}
.cardList--ul {
display: grid;
grid-template-rows: auto;
grid-gap: .5rem;
margin: .5rem 0;
}
.cardItem {
background-color: white;
border: 1px solid #BBB;
border-radius: .25rem;
box-shadow: 0 1px 0 rgba(9,45,66,.25);
padding: .5rem;
display: grid;
grid-template-columns: 5fr 7fr 2fr;
}
And I added JS to handle multiple marquees when needed (list was too long for the viewport):
class marqueeInfo {
constructor(viewer, cardList) {
this.viewer = viewer;
this.cardList = cardList;
if (this.isScrollable) {
this.cardList.style.top = parseInt(this.viewerHeight()) + "px"
}
else {
this.cardList.style.top = "0px"
}
}
viewer() { return this.viewer; }
cardList() { return this.cardList; }
viewerHeight() { return this.viewer.offsetHeight; }
cardListHeight() { return this.cardList.offsetHeight; }
isScrollable() { return this.cardList.offsetHeight > this.viewer.offsetHeight; }
}
var marqueeArray = [];
var marqueeSpeed = 4 //Specify marquee scroll speed (larger is faster 1-10)
var delayb4scroll = 100 //Specify initial delay before marquee starts to scroll on page (2000=2 seconds)
var lastRefresh;
var isRefreshing = false;
var refreshMinutes = 1;
// may be overkill here...
if (window.addEventListener)
window.addEventListener("load", initializeMarqueeHandler, false)
else if (window.attachEvent)
window.attachEvent("onload", initializeMarqueeHandler)
else if (document.getElementById)
window.onload = initializeMarqueeHandler
function initializeMarqueeHandler() {
lastRefresh = new Date();
isRefreshing = false;
var viewers = document.getElementsByClassName("cardViewer");
var cards;
var i;
for (i = 0; i < viewers.length; i++) {
cards = viewers[i].getElementsByClassName("cardList");
if (cards.length != 1)
return;
marqueeArray.push(new marqueeInfo(viewers[i], cards[0]));
}
setTimeout('lefttime=setInterval("scrollMarquees()",30)', delayb4scroll)
}
function scrollMarquees() {
marqueeArray.forEach(function (marquee, index, array) {
if (marquee.isScrollable()) {
var cardHeight = marquee.cardListHeight();
var viewerHeight = marquee.viewerHeight();
var cardTop = parseInt(marquee.cardList.style.top);
var targetTop = 0 - cardHeight;
if (cardTop > targetTop) // are we thru the list?
marquee.cardList.style.top = cardTop - marqueeSpeed + "px" //scroll
else
marquee.cardList.style.top = viewerHeight + 25 + "px";
}
else {
marquee.cardList.style.top = "0px";
}
})
var milliseconds = (new Date()).getTime() - lastRefresh.getTime();
if (milliseconds > (refreshMinutes * 60 * 1000) && !isRefreshing) {
lastRefresh = new Date();
isRefreshing = true;
window.location.reload(true);
}
}
Everything is working as expected - finally.

Related

How can I get playing cards next to each other with CSS?

I am trying to make playing cards using CSS. I followed a YouTube video to make them and they were fine, but now I want to draw multiple cards next to each other, drawing 1 every time I click a button (I am trying to make Blackjack for a school project). The problem is that the cards will be placed under the previous one, and I have tried fiddling with it a bit and I think I have solved one of the issues but I have created another one. Let me show you.
Before, card-container had position absolute which is why i think was a problem, but now the bottom right number and suit is not even inside the container, also it still doesn't place the cards next to each other.
JavaScript that is executed when I click a button
I know that there is a bunch of stuff that there are other problems mainly in the JavaScript like the index of all getClassName, I know how to solve that, this is what I just cant figure out.
var cardcon = document.createElement('div');
cardcon.className = "card-container";
document.getElementById('gugu').appendChild(cardcon);
//
var card = document.createElement('div');
card.className = "card";
document.getElementsByClassName('card-container')[0].appendChild(card);
//
var valuecon = document.createElement('div');
valuecon.className = "value-container container-top";
document.getElementsByClassName('card')[0].appendChild(valuecon);
//
var valuenumber = document.createElement('div');
valuenumber.className = "value-number";
valuenumber.textContent = "7";
document.getElementsByClassName('value-container container-top')[0].appendChild(valuenumber);
//
var valuesuit = document.createElement("div");
valuesuit.className = "value-suit";
valuesuit.innerHTML = "&#9829";
document.getElementsByClassName('value-number')[0].appendChild(valuesuit);
//
var valuedon = document.createElement("div");
valuedon.className = "value-container container-bottom";
document.getElementsByClassName('card')[0].appendChild(valuedon);
//
var valuenumber1 = document.createElement('div');
valuenumber1.className = "value-number";
valuenumber1.textContent = "7";
document.getElementsByClassName('value-container container-bottom')[0].appendChild(valuenumber1);
//
var valuesuit1 = document.createElement("div");
valuesuit1.className = "value-suit";
valuesuit1.innerHTML = "&#9829";
document.getElementsByClassName('value-number')[1].appendChild(valuesuit1);
.card-container {
position: relative;
}
.card {
width: 250px;
height: 350px;
border: 3.5px solid gray;
border-radius: 12.5px;
box-shadow: 10px 10px grey;
background-color: white;
}
.value-container {
position: absolute;
}
.value-number {
font-family: 'Abel', sans-serif;
font-size: 30px;
}
.value-suit {
font-size: 30px;
}
.container-bottom {
bottom: 8px;
right: 16px;
transform: rotate(180deg);
}
.container-top {
top: 20px;
left: 20px;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto auto;
grid-gap: 10px;
background-color: #2196F3;
padding: 10px;
}
<div id="gugu" class="grid-container"></div>
I have changed this part of your css to put down number inside your card
.card-container {width:250px;}
.card {width:100%;}
var cardcon = document.createElement('div');
cardcon.className = "card-container";
document.getElementById('gugu').appendChild(cardcon);
//
var card = document.createElement('div');
card.className = "card";
document.getElementsByClassName('card-container')[0].appendChild(card);
//
var valuecon = document.createElement('div');
valuecon.className = "value-container container-top";
document.getElementsByClassName('card')[0].appendChild(valuecon);
//
var valuenumber = document.createElement('div');
valuenumber.className = "value-number";
valuenumber.textContent = "7";
document.getElementsByClassName('value-container container-top')[0].appendChild(valuenumber);
//
var valuesuit = document.createElement("div");
valuesuit.className = "value-suit";
valuesuit.innerHTML = "&#9829";
document.getElementsByClassName('value-number')[0].appendChild(valuesuit);
//
var valuedon = document.createElement("div");
valuedon.className = "value-container container-bottom";
document.getElementsByClassName('card')[0].appendChild(valuedon);
//
var valuenumber1 = document.createElement('div');
valuenumber1.className = "value-number";
valuenumber1.textContent = "7";
document.getElementsByClassName('value-container container-bottom')[0].appendChild(valuenumber1);
//
var valuesuit1 = document.createElement("div");
valuesuit1.className = "value-suit";
valuesuit1.innerHTML = "&#9829";
document.getElementsByClassName('value-number')[1].appendChild(valuesuit1);
.card-container {
position: relative;
width:250px;
}
.card {
width:100%;
height:350px;
border:3.5px solid gray;
border-radius: 12.5px;
box-shadow: 10px 10px grey;
background-color: white;
}
.value-container {
position: absolute;
}
.value-number {
font-family: 'Abel', sans-serif;
font-size: 30px;
}
.value-suit{
font-size: 30px;
}
.container-bottom{
bottom: 8px;
right: 16px;
transform: rotate(180deg);
}
.container-top{
top:20px;
left:20px;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto auto;
grid-gap: 10px;
background-color: #2196F3;
padding: 10px;
}
<div id="gugu" class="grid-container">
</div>
I'm not sure if I understand your problem but this is my solution.
to card-container add {display : flex}.
&& to card add {position : relative} (this is to fix the numbers floating out of the card)
Use an Inline-Block
<div> tags use by default the css property display:block;. This means that they will automatically claim the entire row that you place them on. The simplest solution is to use an object with the display:inline-block; property. Inline-blocks have all of the same other properties as a block element, but there is no automatic line-break that happens after it. So, if you got your code working right in all other respects using <div>s doing this will fix your problem without having to get messy trying to manipulate your position attributes at all.
To really simplify your code, just use <span> tags instead of <div> tags for your cards since these are inline-blocks by default.

video element to go below previous element if no enough space left on viewport

I am trying to dynamically add video element to a div with each video element has 50vh width. So technically after ever 2 video elements, 3rd video element would be below to the left of screen.
I have tried:
.views-container {
padding: 0;
margin: 0;
font-size: 0;
}
.video-inset {
outline: unset;
position: relative;
margin:0;
padding:0;
}
<div class="views-container background-black" id="container"></div>
And JS
// Current condition is for 3 video elements but could be more
// height width added dynamically and could be different depending on number of elements
// 3 video elements in a row (33.33vw width) if greater than 15 video elements
const container = document.getElementById('container')
const video = document.createElement('video');
video.style.height = 50+"vh"
video.style.width = 50+"vw"
container.append(video);
It works fine only until 2 containers. Please help.
You can use display: grid; on the .views-container. I have used a width and height of 50vw and 50vh. You need to change the 2 (the number of columns) in repeat(2, 1fr) to another number.
const container = document.getElementById('container');
let n = 20; //Total number of videos
for (var i = 1; i <= n; i++) {
const video = document.createElement('video');
if(n > 15){
container.style.gridTemplateColumns = "repeat(3, 1fr)";
video.style.height = "33.33vh";
video.style.width = "33.33vw";
} else{
video.style.height = "50vh";
video.style.width = "50vw";
}
video.src = "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"
container.append(video);
}
.views-container {
padding: 0;
margin: 0;
font-size: 0;
display: grid;
grid-template-columns: repeat(2, 1fr)
}
.video-inset {
outline: unset;
position: relative;
margin: 0;
padding: 0;
}
<div class="views-container background-black" id="container"></div>

Component Fails To Re-Render Correctly Using setState Hook

I am teaching myself to React. I have created a little project to familiarise myself with React. I basically want the slider to adjust the grid size below. However, when changing the slider, it re-renders completely incorrectly. What it should do is create a square grid, with the dimensions equal to the slider value. The grid should always be square, and as the slider value changes, so should the height and width of the square.
The right-hand side column should have 1 column, but as many rows as the square on the left. Right now it does not grow or shrink with the slider. Any changes to the slider value just create 2 squares, with no relation to the slider value.
Before:
After:
Here is what the code looks like (simply paste into App.js after running NPX-create-react-app). If someone could explain how I can get this to work as intended it would be appreciated:
import React, { useState } from "react";
import "./App.css";
class Matrix {
constructor(rows, cols) {
this.rows = rows;
this.cols = cols;
this.size = rows * cols;
this.values = new Array(this.size).fill("");
}
}
function Cell(props) {
return (
<input
className="matrix-component"
id={props.id}
value={props.value}
onChange={(e) => props.onChange(props.id, e.target.value)}
></input>
);
}
function App() {
let [dim, setDim] = useState(3);
let [matrix, setMatrix] = useState(new Matrix(dim, dim));
let [rhs, setRHS] = useState(new Matrix(dim, 1));
function updateMatrix(i, value) {
let new_values = matrix.values.slice();
let new_matrix = new Matrix(matrix.rows, matrix.cols);
new_values[i] = value;
new_matrix.values = new_values;
setMatrix(new_matrix);
}
function updateRHS(i, value) {
let index = i.replace(/\D/g, "");
let new_values = rhs.values.slice();
let new_matrix = new Matrix(matrix.rows, 1);
new_values[index] = value;
new_matrix.values = new_values;
setRHS(new_matrix);
}
function updateSlider(value) {
setDim(value);
}
function handleClick() {
console.log(matrix.values);
console.log(rhs.values);
}
return (
<div className="App">
<div className="content">
<div className="matrix">
<div>
{Array.apply(null, Array(dim)).map(function (x, i) {
const col = Array.apply(null, Array(dim)).map(function (y, j) {
return (
<Cell
key={i * dim + j}
id={i * dim + j}
value={matrix.values[i * dim + j]}
onChange={updateMatrix}
/>
);
});
return <div key={i}>{col}</div>;
})}
</div>
<div>
<div className="rhs">
{Array.apply(null, Array(dim)).map(function (x, i) {
return (
<Cell
key={"rhs" + i}
id={"rhs" + i}
value={rhs.values[i]}
onChange={updateRHS}
/>
);
})}
</div>
</div>
</div>
<button onClick={handleClick}>Solve</button>
</div>
<input
type="range"
min="3"
max="10"
value={dim}
onChange={(event) => updateSlider(event.target.value)}
></input>
</div>
);
}
export default App;
.App {
text-align: center;
width: 500px;
margin: auto;
/* background: grey; */
}
.matrix {
/* float: left; */
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(1, 1fr);
grid-column-gap: 0px;
grid-row-gap: 0px;
padding: 10px;
margin: 10px;
}
.matrix-component {
border-width: thin;
border-style: solid;
border-color: black;
width: 50px;
height: 50px;
}
.rhs {
margin-left: 40px;
display: grid;
}
function updateSlider(value) {
setDim(value);
}
The event.target.value is a string, so you switch dim from an integer to a string. If you convert value into an integer it'll work correctly.
function updateSlider(value) {
setDim(parseInt(value, 10));
}

CSS: Make children inside parent responsive

So I am not using any CSS framework like bootstrap to get responsiveness out of the box which is why I am having trouble making responsive layout.
Please see jsbin
I essentially what to auto-resize colorful boxes based on browser window size eg that should shrink or grow automatically based on window size. Colorful boxes inside their parent should always be in horizontal row but should be able to adjust their width and height like this example.
I tried using flex-wrap: nowrap; but it didn't do the trick :(
Please note that colorful boxes are using position:absolute with parent's position being relative. I am also adding left css property to these boxes via JavaScript to change their position for the sake of sliding animation.
function Carousel(options) {
options = options || {};
// options vars
let speed = options.speed || 1; // animation speed in seconds
let width = options.width || 200;
let height = options.height || 100;
let space = options.space || 30;
// other vars
let container = document.querySelector('.carousel-container .carousel');
let slides = container.querySelectorAll('.carousel-item');
let curSlide = null;
let prevSlide = null;
let nextSlide = null;
if (areSlidesPresent()) {
setup();
}
// functions //
function setup() {
// we assume first slide to be current one as per UI requirements
//slides[0].classList.add("current");
curSlide = slides[0];
// we assume second slide to be next as per UI requirements
nextSlide = slides[1];
// we assume last slide to be prev as per UI requirements
prevSlide = slides[slides.length - 1];
// position elements horizontally
positionSlides();
}
function areSlidesPresent() {
return slides.length > 0;
}
this.getCurrentSlide = function() {
return curSlide;
}
this.getNextSlide = function() {
return nextSlide;
}
this.getPreviousSlide = function() {
return prevSlide;
}
this.setNextSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(nextSlide);
// middle ones
for (let i = 2; i < slides.length; i++) {
allSlides.push(slides[i]);
}
allSlides.push(curSlide);
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
this.setPreviousSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(prevSlide);
allSlides.push(curSlide);
// middle ones
for (let i = 1; i < slides.length - 1; i++) {
allSlides.push(slides[i]);
}
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
function positionSlides() {
curSlide.style.marginLeft = '0px';
for (let i = 0; i < slides.length; i++) {
slides[i].querySelector('.carousel-content').style.width = (width) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height) + 'px';
let elementWidth = getStyle(nextSlide, 'width');
if (i === 0) {
slides[i].style.zIndex = -10;
//slides[i].style.opacity = '1';
slides[i].querySelector('.carousel-content').style.width = (width + 50) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height + 50) + 'px';
} else {
slides[i].style.zIndex = 0;
//slides[i].style.opacity = '0.7';
}
if (i > 0) {
slides[i].style.marginLeft = (space * 2) + 'px';
elementWidth = parseInt(elementWidth, 10) + space;
}
slides[i].style.transition = speed + 's';
slides[i].style.left = (elementWidth * i) + 'px';
}
}
function getStyle(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop)
.replace('px', '')
.replace('em', '');
}
}
// utility
function log(text) {
console.log(text);
}
var options = {
speed: 1, // animation speed
width: 250, // slide width
height: 150, // slide height
space: 25 // space in px between slides
};
var carousel = new Carousel(options);
function selectCurrent() {
log(carousel.getCurrentSlide());
}
function selectNext() {
carousel.setNextSlide();
}
function selectPrev() {
carousel.setPreviousSlide();
}
.carousel-container {
width: auto;
height: auto;
margin: 25px;
display: flex;
align-items: center;
justify-content: center;
}
.carousel {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.carousel .carousel-item {
position: absolute;
transition: transform .5s ease-in-out;
color: #fff;
margin-left: 10px;
-webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(70%, transparent), to(rgba(255, 255, 255, 0.2)));
}
.carousel .carousel-item:first-child .carousel-content {
opacity: 1;
}
.carousel .carousel-item .carousel-title {
font-size: 24px;
text-align: center;
}
.carousel .carousel-item .carousel-content {
font-size: 18px;
font-weight: bold;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
/* temp css below */
body {
background: #2C374A;
padding-top: 150px;
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
margin-top: 150px;
}
.button {
color: #444;
padding: 10px;
width: 60px;
cursor: pointer;
background: #CCC;
text-align: center;
font-weight: bold;
border-radius: 5px;
border-top: 1px solid #FFF;
box-shadow: 0 5px 0 #999;
transition: box-shadow 0.1s, top 0.1s;
margin: 10px;
}
.button:hover,
.button:hover {
color: #000;
}
.button:active,
.button:active {
top: 104px;
box-shadow: 0 1px 0 #999;
}
<div class="carousel-container">
<div class="carousel">
<div class="carousel-item">
<div class="carousel-title">Make a Call</div>
<div class="carousel-content" style="background:#0E6DE8;border:10px solid #78B1FA">Slide One</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Message</div>
<div class="carousel-content" style="background:#D90080;border:10px solid #E357A9">Slide Two</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Picture</div>
<div class="carousel-content" style="background:#FEC601;border:10px solid #FFDD64">Slide Three</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Video</div>
<div class="carousel-content" style="background:#3DB365;border:10px solid #90E0AB">Slide Four</div>
</div>
</div>
</div>
<div class="navigation">
<div class="button" onclick="selectNext()">Next</div>
<div class="button" onclick="selectCurrent()">Select</div>
<div class="button" onclick="selectPrev()">Prev</div>
</div>
Problem here was:
Width was hard-coded in your JS, so if width is in px it can't be responsive.
By applying position:absolute to you carousel-item, it forced the children to get out of the box.
What I did:
Got rid of the static width and other functionalities related to width from your JS
Removed position:absolute from carousel-item
Let me know if this is what you are expecting.
function Carousel(options) {
options = options || {};
// options vars
let speed = options.speed || 1; // animation speed in seconds
// let width = options.width || 100;
let height = options.height || 100;
let space = options.space || 30;
// other vars
let container = document.querySelector('.carousel-container .carousel');
let slides = container.querySelectorAll('.carousel-item');
let curSlide = null;
let prevSlide = null;
let nextSlide = null;
if (areSlidesPresent()) {
setup();
}
// functions //
function setup() {
// we assume first slide to be current one as per UI requirements
//slides[0].classList.add("current");
curSlide = slides[0];
// we assume second slide to be next as per UI requirements
nextSlide = slides[1];
// we assume last slide to be prev as per UI requirements
prevSlide = slides[slides.length - 1];
// position elements horizontally
positionSlides();
}
function areSlidesPresent() {
return slides.length > 0;
}
this.getCurrentSlide = function() {
return curSlide;
}
this.getNextSlide = function() {
return nextSlide;
}
this.getPreviousSlide = function() {
return prevSlide;
}
this.setNextSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(nextSlide);
// middle ones
for (let i = 2; i < slides.length; i++) {
allSlides.push(slides[i]);
}
allSlides.push(curSlide);
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
this.setPreviousSlide = function() {
if (areSlidesPresent()) {
let allSlides = [];
// build new order of slides
allSlides.push(prevSlide);
allSlides.push(curSlide);
// middle ones
for (let i = 1; i < slides.length - 1; i++) {
allSlides.push(slides[i]);
}
// now add to DOM after cleaning previous slide order
for (let i = 0; i < allSlides.length; i++) {
container.appendChild(allSlides[i]);
}
slides = allSlides;
setup();
}
}
function positionSlides() {
curSlide.style.marginLeft = '0px';
for (let i = 0; i < slides.length; i++) {
// slides[i].querySelector('.carousel-content').style.width = (width) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height) + 'px';
let elementWidth = getStyle(nextSlide, 'width');
if (i === 0) {
slides[i].style.zIndex = -10;
//slides[i].style.opacity = '1';
// slides[i].querySelector('.carousel-content').style.width = (width + 50) + 'px';
slides[i].querySelector('.carousel-content').style.height = (height + 50) + 'px';
} else {
slides[i].style.zIndex = 0;
//slides[i].style.opacity = '0.7';
}
if (i > 0) {
slides[i].style.marginLeft = (space * 2) + 'px';
// elementWidth = parseInt(elementWidth, 10) + space;
}
slides[i].style.transition = speed + 's';
// slides[i].style.left = (elementWidth * i) + 'px';
}
}
function getStyle(el, prop) {
return window.getComputedStyle(el, null).getPropertyValue(prop)
.replace('px', '')
.replace('em', '');
}
}
// utility
function log(text) {
console.log(text);
}
var options = {
speed: 1, // animation speed
width: 250, // slide width
height: 150, // slide height
space: 25 // space in px between slides
};
var carousel = new Carousel(options);
function selectCurrent() {
log(carousel.getCurrentSlide());
}
function selectNext() {
carousel.setNextSlide();
}
function selectPrev() {
carousel.setPreviousSlide();
}
.carousel-container {
height: auto;
margin: 25px;
display: flex;
}
.carousel {
flex: 1;
height: 100%;
width: 100vh;
/* overflow:hidden; */
display: flex;
align-items: center;
justify-content: center;
}
.carousel .carousel-item {
transition: transform .5s ease-in-out;
color: #fff;
flex: 1;
margin-left: 10px;
-webkit-box-reflect: below 10px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(70%, transparent), to(rgba(255, 255, 255, 0.2)));
}
.carousel .carousel-item:first-child .carousel-content {
opacity: 1;
}
.carousel .carousel-item .carousel-title {
font-size: 24px;
text-align: center;
}
.carousel .carousel-item .carousel-content {
font-size: 18px;
font-weight: bold;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
/* temp css below */
body {
background: #2C374A;
}
.navigation {
display: flex;
align-items: center;
justify-content: center;
}
.button {
color: #444;
padding: 10px;
width: 60px;
cursor: pointer;
background: #CCC;
text-align: center;
font-weight: bold;
border-radius: 5px;
border-top: 1px solid #FFF;
box-shadow: 0 5px 0 #999;
transition: box-shadow 0.1s, top 0.1s;
margin: 10px;
}
.button:hover,
.button:hover {
color: #000;
}
.button:active,
.button:active {
box-shadow: 0 1px 0 #999;
}
<div class="navigation">
<div class="button" onclick="selectNext()">Next</div>
<div class="button" onclick="selectCurrent()">Select</div>
<div class="button" onclick="selectPrev()">Prev</div>
</div>
<div class="carousel-container">
<div class="carousel">
<div class="carousel-item">
<div class="carousel-title">Make a Call</div>
<div class="carousel-content" style="background:#0E6DE8;border:10px solid #78B1FA">Slide One</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Message</div>
<div class="carousel-content" style="background:#D90080;border:10px solid #E357A9">Slide Two</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Picture</div>
<div class="carousel-content" style="background:#FEC601;border:10px solid #FFDD64">Slide Three</div>
</div>
<div class="carousel-item">
<div class="carousel-title">Send a Video</div>
<div class="carousel-content" style="background:#3DB365;border:10px solid #90E0AB">Slide Four</div>
</div>
</div>
</div>

Is there a way to re-arranging the order of blocks (flex) in Css

I wanna change the order of my elements (divs flex displayed) in mobile, the initial structure is already done but i found a difficulties to customize it to satisfy my needs in mobile, any help ?
The key issue here is that the flexbox order property, while powerful, can't turn a sibling element into a child element. Only javascript can do that.
Here is one approach that works using CSS flexbox and CSS #media queries but which employs javascript (rather than the flexbox order property) to move .div3 across the DOM, so that it becomes a child element of .child-container:
var narrowScreen = window.matchMedia("(max-width:600px)");
var screenIsNarrow = false;
var parentContainer = document.getElementsByClassName('parent-container')[0];
var childContainer = document.getElementsByClassName('child-container')[0];
var div1 = document.getElementsByClassName('div1')[0];
var div2 = document.getElementsByClassName('div2')[0];
var div3 = document.getElementsByClassName('div3')[0];
function checkScreenWidth() {
if ((narrowScreen.matches) && (screenIsNarrow === false)) {
childContainer.insertBefore(div3, div1);
childContainer.insertBefore(div2, div3);
screenIsNarrow = true;
}
else if ((!narrowScreen.matches) && (screenIsNarrow === true)) {
childContainer.insertBefore(div1, div2);
parentContainer.insertBefore(div3, childContainer);
parentContainer.insertBefore(childContainer, div3);
screenIsNarrow = false;
}
}
window.addEventListener('resize', checkScreenWidth, false);
window.addEventListener('load', checkScreenWidth, false);
.parent-container {
display: flex;
width: 90vw;
min-height: 200px;
font-size: 24px;
line-height: 200px;
text-align: center;
color: rgb(255, 255, 255);
}
.child-container {
display: flex;
flex: 1 0 74%;
padding: 24px 4vw;
margin-right: 1vw;
background-color: rgb(191,191,191);
}
.div1, .div2 {
flex: 1 1 45%;
margin: 3px 0.5vw;
background-color: rgb(83,83,83);
}
.div3 {
flex: 1 0 24%;
background-color: rgb(127,127,127);
}
#media only screen and (max-width:600px) {
.child-container {
display: inline-block;
}
.div1, .div2, .div3 {
margin: 6px;
}
}
<div class="parent-container">
<div class="child-container">
<div class="div1">One</div>
<div class="div2">Two</div>
</div>
<div class="div3">Three</div>
</div>