I currently make a tab which the tab content is containing iframe. I want it to every time the tab is clicked, the iframe reload the page.
But when I inspected, the source attributes exist in every iframe, and the issues shows up that states: Uncaught TypeError: Cannot read properties of undefined (reading 'setAttribute'). I'm very new in JavaScript, and have no idea to code. Please help me through this. Thank you so much.
So, here's the code :
let tabs = document.querySelectorAll('.tab');
let content = document.querySelectorAll('.content-item');
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener('click', () => tabClick(i));
}
function tabClick(currentTab) {
removeActive();
tabs[currentTab].classList.add('active');
content[currentTab].classList.add('active');
content[currentTab].removeAttribute('src');
}
function removeActive() {
for (let i = 0; i < tabs.length; i++) {
tabs[i].classList.remove('active');
content[i].classList.remove('active');
content[i].setAttribute('src', content[i].getAttribute('data-src'));
}
}
.container {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.tabs {
display: flex;
justify-content: center;
width: 100%;
}
.tab {
font-size: 16px;
padding: 5px 15px;
cursor: pointer;
}
.tab.active {
background-color: rgb(250, 97, 9);
}
.content {
width: 100vw;
margin-top: 50px;
}
.content-item {
display: none;
padding: 0px;
border: none;
}
.content-item.active {
display: flex;
justify-content: center;
}
.content-iframe {
border: none;
padding: 0px;
margin: 0px;
width: 100vw;
height: 50vh;
}
<div class="container">
<div class="tabs">
<div class="tab active">Tokyo</div>
<div class="tab">Paris</div>
<div class="tab">Washington</div>
<div class="tab">Jakarta</div>
<div class="tab">London</div>
</div>
<div class="content">
<div class="content-item active">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Tokyo" src="https://en.wikipedia.org/wiki/Tokyo" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Paris" src="https://en.wikipedia.org/wiki/Paris" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Washington" src="https://en.wikipedia.org/wiki/Washington" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Jakarta" src="https://en.wikipedia.org/wiki/Jakarta" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/London" src="https://en.wikipedia.org/wiki/London" loading="lazy"></iframe>
</div>
</div>
</div>
First, I think you were doing the two iframe operations in the wrong place. I've reversed them so the iframe is cleared in removeActive(). Then, you weren't targeting the iframes with your source updates.
Otherwise you're doing great. Keep it up!
let tabs = document.querySelectorAll('.tab');
let content = document.querySelectorAll('.content-item');
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener('click', () => tabClick(i));
}
function tabClick(currentTab) {
const iframe = content[currentTab].querySelector('iframe');
removeActive();
tabs[currentTab].classList.add('active');
content[currentTab].classList.add('active');
iframe.setAttribute('src', iframe.getAttribute('data-src'));
}
function removeActive() {
for (let i = 0; i < tabs.length; i++) {
tabs[i].classList.remove('active');
content[i].classList.remove('active');
content[i].querySelector('iframe').removeAttribute('src');
}
}
.container {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.tabs {
display: flex;
justify-content: center;
width: 100%;
}
.tab {
font-size: 16px;
padding: 5px 15px;
cursor: pointer;
}
.tab.active {
background-color: rgb(250, 97, 9);
}
.content {
width: 100vw;
margin-top: 50px;
}
.content-item {
display: none;
padding: 0px;
border: none;
}
.content-item.active {
display: flex;
justify-content: center;
}
.content-iframe {
border: none;
padding: 0px;
margin: 0px;
width: 100vw;
height: 50vh;
}
<div class="container">
<div class="tabs">
<div class="tab active">Tokyo</div>
<div class="tab">Paris</div>
<div class="tab">Washington</div>
<div class="tab">Jakarta</div>
<div class="tab">London</div>
</div>
<div class="content">
<div class="content-item active">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Tokyo" src="https://en.wikipedia.org/wiki/Tokyo" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Paris" src="https://en.wikipedia.org/wiki/Paris" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Washington" src="https://en.wikipedia.org/wiki/Washington" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/Jakarta" src="https://en.wikipedia.org/wiki/Jakarta" loading="lazy"></iframe>
</div>
<div class="content-item">
<iframe class="content-iframe" data-src="https://en.wikipedia.org/wiki/London" src="https://en.wikipedia.org/wiki/London" loading="lazy"></iframe>
</div>
</div>
</div>
Related
Sorry, I repost the problem:
I want to remove a single container when their border right x become inferior to the border left x of their parent. It work fine with visibility hidden, but not with remove() as it remove all the containers.
Here the complete code of the problem...
Here is the JavaScript, for what the result is unexpected
let isPassed = setInterval(function() {
let containers = document.querySelectorAll(".container");
let division = document.querySelector(".division")
containers.forEach((container) => {
let containerRight = parseInt(container.getBoundingClientRect().right);
let zoneLeft = parseInt(division.getBoundingClientRect().left);
if (containerRight <= zoneLeft) {
//container.style.visibility = "hidden"; // work fine
//container.style.display = "none"; // hide all the container
container.remove() // remove all the container
}
})
}, 100);
body,
html {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.division {
position: relative;
display: flex;
flex-direction: row;
width: 320px;
height: 128px;
border: 1px solid red;
/* overflow: hidden; */
}
.container {
display: flex;
flex-direction: column;
position: relative;
bottom: 0;
height: 128px;
width: 64px;
display: flex;
align-items: center;
visibility: visible;
animation: translation 5s linear;
border: 1px solid rgb(0, 0, 0);
}
.container>div {
display: flex;
position: relative;
justify-content: center;
width: 64px;
height: 64px;
border: 1px solid black;
}
#keyframes translation {
0% {
right: 64px;
}
100% {
right: 896px;
}
}
<div class="division">
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
</div>
If you remove() the most left container, the other contains will move over to fill the gap that is there by removing the previous containers.
When they move, they instantly match your if, and therefore they are removed them self.
Fix 1
Use justify-content: flex-end; on the .division so that the containers are aligned from the end of the box, so it won't overlap if you remove any of them. This way remove() will work as expected
let isPassed = setInterval(function() {
let containers = document.querySelectorAll(".container");
let division = document.querySelector(".division")
containers.forEach((container) => {
let containerRight = parseInt(container.getBoundingClientRect().right);
let zoneLeft = parseInt(division.getBoundingClientRect().left);
if (containerRight <= zoneLeft) {
container.remove();
}
})
}, 100);
body,
html {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.division {
justify-content: flex-end;
position: relative;
display: flex;
flex-direction: row;
width: 320px;
height: 128px;
border: 1px solid red;
/* overflow: hidden; */
}
.container {
display: flex;
flex-direction: column;
position: relative;
bottom: 0;
height: 128px;
width: 64px;
display: flex;
align-items: center;
visibility: visible;
animation: translation 5s linear;
border: 1px solid rgb(0, 0, 0);
}
.container>div {
display: flex;
position: relative;
justify-content: center;
width: 64px;
height: 64px;
border: 1px solid black;
}
#keyframes translation {
0% {
right: 64px;
}
100% {
right: 896px;
}
}
<div class="division">
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
</div>
Fix 2
Using style.visibility = "hidden" is your best option, if you don't want to change the HTML/CSS to prevent the moving of the containers when you remove() one.
let isPassed = setInterval(function() {
let containers = document.querySelectorAll(".container");
let division = document.querySelector(".division")
containers.forEach((container) => {
let containerRight = parseInt(container.getBoundingClientRect().right);
let zoneLeft = parseInt(division.getBoundingClientRect().left);
if (containerRight <= zoneLeft) {
container.style.visibility = "hidden"; // work fine
}
})
}, 100);
body,
html {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}
.division {
position: relative;
display: flex;
flex-direction: row;
width: 320px;
height: 128px;
border: 1px solid red;
/* overflow: hidden; */
}
.container {
display: flex;
flex-direction: column;
position: relative;
bottom: 0;
height: 128px;
width: 64px;
display: flex;
align-items: center;
visibility: visible;
animation: translation 5s linear;
border: 1px solid rgb(0, 0, 0);
}
.container>div {
display: flex;
position: relative;
justify-content: center;
width: 64px;
height: 64px;
border: 1px solid black;
}
#keyframes translation {
0% {
right: 64px;
}
100% {
right: 896px;
}
}
<div class="division">
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="container A">
<div class="box1"></div>
<div class="box2"></div>
</div>
</div>
Ok, let's say that I have two buttons, a container with two divs and below I have my footer, like this:
<button id="bt1">Show all</button>
<button id="bt2">Show curses</button>
<div class="container">
<div class="one"></div>
<div class="two"></div>
</div>
<footer></footer>
I'm displaying content inside my divs. Div "one" has more height, much more. In order to hide div "two" and don't overlap content, I use opacity:0.
I have two buttons, to show or to hide div "one" or "two" (using jQuery).
But if I only use opacity:0 to hide div "one" when I show div "two", the page leaves a big space empty (due to div "one" has more height than div "two"). As here:
enter image description here
So I decided to use display:none to hide div "one", in order to don't leave space and just show the necessary space for div "two". But my footer goes up!! And overlaps content with div "two".
Here is the image: enter image description here
How can I solve this? Any ideas? I realized that my footer moves because not finding the content of div "one", it goes up. Sorry for my english haha
Here I leave you guys an excelent example of what happens to me, you can COPY and run:
HTML:
var cont_all = $('.one');
var bt1 = $('#bt1');
var cont_curses = $('.two');
var bt2 = $('#bt2');
bt2.click(function(){
cont_all.css('display', 'none');
cont_curses.css('opacity', '1');
});
bt1.click(function(){
cont_curses.css('opacity', '0');
cont_all.css('display', 'flex');
});
h2 {
text-align: center;
font-size: 40px;
}
.container {
margin-top: 50px;
position: relative;
height: auto;
padding-bottom: 50px;
}
.one, .two {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
height: auto;
}
.one {
overflow: hidden;
}
.two {
width: 100%;
position: absolute;
top: 0px;
opacity: 0;
}
.chart {
width: 30%;
height: 200px;
margin: 15px;
background: #2096CE;
}
.curse {
width: 30%;
height: 200px;
margin: 15px;
background: #23AD5A;
}
footer {
height: 200px;
background: black;
color: white;
display: flex;
justify-content: center;
text-align: center;
}
p {
text-align: center;
font-size: 35px;
margin: auto 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
<h2>Problem with divs</h2>
</header>
<button id="bt1">Show all</button>
<button id="bt2">Show curses</button>
<div class="container">
<div class="one">
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
</div>
<div class="two">
<div class="curse"></div>
<div class="curse"></div>
<div class="curse"></div>
<div class="curse"></div>
</div>
</div>
<footer>
<p>I'm the footer</p>
</footer>
Well it's not the same at all, because it's a big project, but basically is that.
Full answer
check the max-height toggles
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Display None</title>
<link rel="stylesheet" href="estilos.css">
<style>
h2 {
text-align: center;
font-size: 40px;
}
.container {
margin-top: 50px;
position: relative;
height: auto;
padding-bottom: 50px;
}
.one, .two {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
height: auto;
overflow: hidden;
}
.chart {
width: 30%;
height: 200px;
margin: 15px;
background: #2096CE;
}
.curse {
width: 30%;
height: 200px;
margin: 15px;
background: #23AD5A;
}
footer {
height: 200px;
background: black;
color: white;
display: flex;
justify-content: center;
text-align: center;
}
p {
text-align: center;
font-size: 35px;
margin: auto 0;
}
</style>
</head>
<body>
<header>
<h2>Problem with divs</h2>
</header>
<button id="bt1">Show all</button>
<button id="bt2">Show curses</button>
<div class="container">
<div class="one">
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
<div class="chart"></div>
</div>
<div class="two">
<div class="curse"></div>
<div class="curse"></div>
<div class="curse"></div>
<div class="curse"></div>
</div>
</div>
<footer>
<p>I'm the footer</p>
</footer>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
var cont_all = $('.one');
var bt1 = $('#bt1');
var cont_curses = $('.two');
var bt2 = $('#bt2');
bt2.click(function(){
cont_all.css('max-height', '0px');
cont_curses.css('max-height', '100%');
});
bt1.click(function(){
cont_curses.css('max-height', '0px');
cont_all.css('max-height', '100%');
});
</script>
</body>
</html>
I am slightly changed #alexkarpen answer. Instead of max-height you can also use fadeIn() and fadeOut() jquery function. it looks a little bit cool
var cont_all = $('.one');
var bt1 = $('#bt1');
var cont_curses = $('.two');
var bt2 = $('#bt2');
var cont_project = $('.three');
var bt3 = $('#bt3');
bt2.click(function(){
cont_all.fadeOut("slow");
cont_project.fadeOut();
cont_curses.fadeIn("slow");
});
bt3.click(function(){
cont_all.fadeOut();
cont_curses.fadeOut();
cont_project.fadeIn("slow");
});
bt1.click(function(){
cont_curses.fadeIn("slow");
cont_project.fadeIn("slow");
cont_all.fadeIn("slow");
});
.container {
margin-top: 30px;
position: relative;
height: auto;
padding-bottom: 50px;
}
.one, .two, .three {
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
height: auto;
overflow: hidden;
}
.card {
width: 25%;
height: 200px;
margin: 15px;
}
.chart {
background: #2096CE;
}
.curse {
background: #23AD5A;
}
.project {
background: pink;
}
footer {
height: 200px;
background: black;
color: white;
display: flex;
justify-content: center;
text-align: center;
}
p {
text-align: center;
font-size: 35px;
margin: auto 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="bt1">Show All</button>
<button id="bt2">Show Curses</button>
<button id="bt3">Show Projects</button>
<div class="container">
<div class="one">
<div class="card chart"></div>
<div class="card chart"></div>
<div class="card chart"></div>
<div class="card chart"></div>
<div class="card chart"></div>
<div class="card chart"></div>
</div>
<div class="two">
<div class="card curse"></div>
<div class="card curse"></div>
<div class="card curse"></div>
</div>
<div class="three">
<div class="card project"></div>
<div class="card project"></div>
</div>
</div>
<footer>
<p>I'm the footer</p>
</footer>
Try this:
footer { height: 200px; background: black; color: white; display: flex; justify-content: center; text-align: center; position:fixed; bottom: 0px; }
I have a problem with my structure, I want to have different divs, each one of those with a header and a body, which is hidden by defect. There's a button in each div's header to show each div's body if it's button is clicked. If you press the same button again, the body hides again. I want to do it with the same function because I will generate more and more of this divs, that's why I can't be copying the same function again and again. Is there any way to do that? There is my code:
function OpenHideFlexColumn() {
var x = document.getElementById("Body");
if (x.style.display === "flex") {
x.style.display = "none";
} else {
x.style.display = "flex";
}
}
body {
background-color: lightblue;
}
a {
outline: 0;
text-decoration: none;
}
.area {
width: 100%;
display: flex;
flex-direction: column;
}
.module {
height: auto;
width: auto;
margin: 11px;
padding: 11px;
display: flex;
flex-direction: column;
background-color: white;
}
.header {
height: auto;
width: 100%;
display: inline-flex;
font-size: 24px;
}
.options {
height: auto;
width: auto;
margin-left: auto;
margin-right: 0;
display: inline-flex;
}
.button {
height: 20px;
width: auto;
padding: 5px;
background-color: lightgrey;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
}
.body {
height: auto;
width: auto;
display: none;
flex-direction: column;
}
<div id="infocontent-1" class="area">
<!--MODULE-->
<div class="module">
<div class="header">
<b>Title</b>
<div class="options">
<!-- Other function button-->
<a class="button">
..
</a>
<!--Hide/Show button-->
<a class="button" onclick="OpenHideFlexColumn();">
<b>Push me to Open/Hide</b>
</a>
</div>
</div>
<div class="body" id="Body">
Body text.....
</div>
</div>
<!--MODULE 2-->
<div class="module">
<div class="header">
<b>Title</b>
<div class="options">
<!-- Other function button-->
<a class="button">
..
</a>
<!--Hide/Show button-->
<a class="button" onclick="OpenHideFlexColumn();">
<b>Push me to Open/Hide</b>
</a>
</div>
</div>
<div class="body" id="Body">
Body text.....
</div>
</div>
</div>
Use this inside function and parentNode
<!DOCTYPE html>
<html lang="es">
<head>
<style>
body{
background-color: lightblue;
}
a {
outline: 0;
text-decoration: none;
}
.area{
width: 100%;
display: flex;
flex-direction: column;
}
.module{
height: auto;
width: auto;
margin: 11px;
padding: 11px;
display: flex;
flex-direction: column;
background-color: white;
}
.header{
height: auto;
width: 100%;
display: inline-flex;
font-size: 24px;
}
.options{
height: auto;
width: auto;
margin-left: auto;
margin-right: 0;
display: inline-flex;
}
.button{
height: 20px;
width: auto;
padding: 5px;
background-color: lightgrey;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
}
.body{
height: auto;
width: auto;
display: none;
flex-direction: column;
}
</style>
</head>
<body>
<div id="infocontent-1" class="area">
<!--MODULE-->
<div class="module">
<div class="header">
<b>Title</b>
<div class="options">
<!-- Other function button-->
<a class="button">
..
</a>
<!--Hide/Show button-->
<a class="button" onclick="OpenHideFlexColumn(this);">
<b>Push me to Open/Hide</b>
</a>
</div>
</div>
<div class="body" id="Body">
Body text.....
</div>
</div>
<!--MODULE 2-->
<div class="module">
<div class="header">
<b>Title</b>
<div class="options">
<!-- Other function button-->
<a class="button">
..
</a>
<!--Hide/Show button-->
<a class="button" onclick="OpenHideFlexColumn(this);">
<b>Push me to Open/Hide</b>
</a>
</div>
</div>
<div class="body" id="Body">
Body text.....
</div>
</div>
</div>
<script>
function OpenHideFlexColumn(e) {
var x = e.parentNode.parentNode.parentNode.querySelector('.body');
if (x.style.display === "flex") {
x.style.display = "none";
} else {
x.style.display = "flex";
}
}
</script>
</body>
</html>
Anytime you have an onclick you automatically have access to the event. if we look at event.target.parentNode we get the element needed.
function OpenHideFlexColumn() {
var e = event.target.parentNode
var x = e.parentNode.parentNode.parentNode.querySelector('.body');
if (x.style.display === "flex") {
x.style.display = "none";
} else {
x.style.display = "flex";
}
}
body{
background-color: lightblue;
}
a {
outline: 0;
text-decoration: none;
}
.area{
width: 100%;
display: flex;
flex-direction: column;
}
.module{
height: auto;
width: auto;
margin: 11px;
padding: 11px;
display: flex;
flex-direction: column;
background-color: white;
}
.header{
height: auto;
width: 100%;
display: inline-flex;
font-size: 24px;
}
.options{
height: auto;
width: auto;
margin-left: auto;
margin-right: 0;
display: inline-flex;
}
.button{
height: 20px;
width: auto;
padding: 5px;
background-color: lightgrey;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
}
.body{
height: auto;
width: auto;
display: none;
flex-direction: column;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="infocontent-1" class="area">
<!--MODULE-->
<div class="module">
<div class="header">
<b>Title</b>
<div class="options">
<!-- Other function button-->
<a class="button">
..
</a>
<!--Hide/Show button-->
<a class="button" onclick="OpenHideFlexColumn();">
<b>Push me to Open/Hide</b>
</a>
</div>
</div>
<div class="body" id="Body">
Body text.....
</div>
</div>
<!--MODULE 2-->
<div class="module">
<div class="header">
<b>Title</b>
<div class="options">
<!-- Other function button-->
<a class="button">
..
</a>
<!--Hide/Show button-->
<a class="button" onclick="OpenHideFlexColumn(this);">
<b>Push me to Open/Hide</b>
</a>
</div>
</div>
<div class="body" id="Body">
Body text.....
</div>
</div>
</div>
</body>
</html>
In the snippet provided, I have 3 sections: The first contains a single image, the second has two images, and the last one has no images.
I would like for the .image class within the first section to be 100% in width only if there is no other .image div present.
However, once there is another .image div present, (as shown in the second section), I would like it to default back to 50% width.
How should I execute this?
$(function() {
$('.container > .section').each(function() {
if (!$(this).find(".image").length) {
$(this).before('<div class="noimage">No images to display.</div>');
}
});
});
body {
font-size: 16px;
margin: 0;
padding: 0;
border: 0;
}
h1 {
font-size: 22px;
margin-top: 0;
margin-bottom: 10px;
}
.container {
box-sizing: border-box;
overflow: auto;
}
.image {
float: left;
display: block;
width: 50%;
line-height: 0;
}
.image img {
width: 100%;
height: auto;
}
.container {
margin: 0 auto;
max-width: 300px;
border: 1px solid lightgrey;
padding: 10px;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- 1 Image -->
<div class="container">
<h1>Section With 1 Image:</h1>
<div class="section">
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/pear-flat.png"></div>
</div>
</div>
<!-- 2 Images -->
<div class="container">
<h1>Section With 2 Images:</h1>
<div class="section">
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/ice-cream-cone-flat.png"></div>
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/orange-flat.png"></div>
</div>
</div>
<!-- No Images -->
<div class="container">
<h1>Section With No Images:</h1>
<div class="section"></div>
</div>
You could display the section as a table and the div.image as a table-cell. Then the image would resize according to the number of "cell's" (div.image's) present.
div.container{
display: 100%;
}
div.section{
width: 100%;
display: table;
}
div.section div.image{
display: table-cell;
}
div.section div.image img{
width: 100%;
height: auto;
}
Here's a JSFiddle:
https://jsfiddle.net/ColiniloC/Lnnkpx6L/
Figured out a simpler solution with flexbox:
$(function() {
$('.container > .section').each(function() {
if (!$(this).find(".image").length) {
$(this).before('<div class="noimage">No images to display.</div>');
}
});
});
body {
font-size: 16px;
margin: 0;
padding: 0;
border: 0;
}
h1 {
font-size: 22px;
margin-top: 0;
margin-bottom: 10px;
}
.container {
box-sizing: border-box;
margin: 0 auto;
max-width: 300px;
border: 1px solid lightgrey;
padding: 10px;
display: block;
}
.section {
display: flex;
flex-wrap: wrap;
overflow: hidden;
align-items: center;
margin: 0 -5px;
}
.image {
flex: 1 1 50%;
line-height: 0;
width: 100%;
padding: 0 5px;
box-sizing: border-box;
}
.container .image:nth-of-type(n+3) {
padding-top: 10px;
}
.image img {
width: 100%;
height: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- 1 Image -->
<div class="container">
<h1>Section With 1 Image:</h1>
<div class="section">
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/pear-flat.png"></div>
</div>
</div>
<!-- 2 Images -->
<div class="container">
<h1>Section With 2 Images:</h1>
<div class="section">
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/pear-flat.png"></div>
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/ice-cream-cone-flat.png"></div>
</div>
</div>
<!-- 4 Images -->
<div class="container">
<h1>Section With 4 Images:</h1>
<div class="section">
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/pear-flat.png"></div>
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/ice-cream-cone-flat.png"></div>
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/orange-flat.png"></div>
<div class="image"><img src="https://freeiconshop.com/wp-content/uploads/edd/burger-flat.png"></div>
</div>
</div>
<!-- No Images -->
<div class="container">
<h1>Section With No Images:</h1>
<div class="section"></div>
</div>
I'm facing a problem where I would like an anchor flexbox child to take all remaining height available. I thought that adding flex-grow: 1 would suffice but it is not working. The div inside the anchor does not take the full height.
Question: Is there a way to make it work without converting my plain anchor to a flexbox element?
Here is a codepen illustrating the issue:
https://codepen.io/alansouzati/pen/YVpYeO
I've created 3 tiles where the first one has the anchor to exemplify. You can see that the price does not align with the other siblings.
.plain is not a flex parent, so setting flex-grow: 1 on .service doesn't do anything.
Just add display: flex to .plain
.tiles {
display: flex;
flex-wrap: wrap;
background-color: #d3d3d3;
padding: 12px;
justify-content: center;
}
.tile {
display: flex;
border: 1px solid #333;
flex-basis: 200px;
background-color: white;
margin: 12px;
flex-direction: column;
}
.tile:hover {
background-color: #f1f1f1;
}
.service {
display: flex;
flex-direction: column;
padding: 12px;
flex-grow: 1;
}
.service-body {
flex-grow: 1;
}
p {
color: #a8a8a8;
}
.plain {
margin: 0;
color:inherit;
text-decoration:none;
flex-grow: 1;
display: flex;
}
<div class='tiles'>
<div class='tile'>
<a href="http://google.com" class='plain' target="_blank">
<div class='service'>
<h2>Service 1</h2>
<div class='service-body'>
<p>This is a sample service</p>
</div>
<span>$9.99</span>
</div>
</a>
</div>
<div class='tile'>
<div class='service'>
<h2>Service 2</h2>
<div class='service-body'>
<p>This is a sample service</p>
</div>
<span>$9.99</span>
</div>
</div>
<div class='tile'>
<div class='service'>
<h2>Service 3</h2>
<div class='service-body'>
<p>This is a sample service with a long text that will make things render differently</p>
</div>
<span>$9.99</span>
</div>
</div>
</div>
See Below. I made the ".service" after the anchor tag absolute and relative to the main container. Hope it helps
.tiles {
display: flex;
flex-wrap: wrap;
background-color: #d3d3d3;
padding: 12px;
justify-content: center;
}
.tile {
display: flex;
border: 1px solid #333;
flex-basis: 200px;
background-color: white;
margin: 12px;
flex-direction: column;
position: relative;/**Added Code**/
}
.tile:hover {
background-color: #f1f1f1;
}
.service {
display: flex;
flex-direction: column;
padding: 12px;
flex-grow: 1;
}
.service-body {
flex-grow: 1;
}
p {
color: #a8a8a8;
}
.plain {
margin: 0;
color:inherit;
text-decoration:none;
flex-grow: 1;
}
/**Added Code**/
.plain > .service {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<div class='tiles'>
<div class='tile'>
<a href="http://google.com" class='plain' target="_blank">
<div class='service'>
<h2>Service 1</h2>
<div class='service-body'>
<p>This is a sample service</p>
</div>
<span>$9.99</span>
</div>
</a>
</div>
<div class='tile'>
<div class='service'>
<h2>Service 2</h2>
<div class='service-body'>
<p>This is a sample service</p>
</div>
<span>$9.99</span>
</div>
</div>
<div class='tile'>
<div class='service'>
<h2>Service 3</h2>
<div class='service-body'>
<p>This is a sample service with a long text that will make things render differently</p>
</div>
<span>$9.99</span>
</div>
</div>
</div>