jquery display only 1 element active - javascript

I created this code, click on a picture and you'll come out the description below the image.
I would like to improve this code, so I want to be active only one description of a time, so if I click on a image see the description of that just clicked, and hide the last activated.
maybe with the code is more clear http://codepen.io/mp1985/pen/qOrpQX
$( ".spec").click(function() {
$(this).find(".image, .details-spec").toggle();
$(this).find(".block-content").toggleClass('white');
});
I tried with toggle(), toggleClass() and not() but without success.
any idea?
thanks

You can use not() here to avoid clicked element from selector
var $spec = $(".spec").click(function() {
// caching selector $(".spec") for future use
$spec
.not(this)
// avoiding clicked element
.find(".image")
// getting image selector
.show()
// showing back image
.end()
// back to previous selector
.find(".details-spec")
// getting details
.hide()
// hiding it
.end()
// back to previous selector
.find(".block-content")
// getting block content
.removeClass('white');
// removing class white
$(this)
.find(".image, .details-spec")
// getting elements by class
.toggle()
// toggling visibility
.end()
// back to previous selector
.find(".block-content")
// getting block content
.toggleClass('white');
// toggling class white
});
.block {
position: relative;
height: 300px;
width: 100%;
overflow: hidden;
background: #f9bda1;
margin-bottom: 1em;
}
.one-thirds > .block {
background-color: #484343;
cursor: pointer;
}
.block .image {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.one-thirds {
width: 32%;
float: left;
margin-right: 1%;
}
.full {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
h3 {
font-size: 20px;
}
.details-spec {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
}
.white {
color: white;
}
.active > .image {
visibility: hidden;
}
.active .details-spec {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<div class='one-thirds'>
<div class="block square spec">
<div class="full image" style="background-image:url('http://lorempixel.com/300/300/');"></div>
<div class="block-content full">
<h3>Title:</h3>
<div class="details-spec">
Lorem Lorem Lorem Lorem LoremLorem Lorem Lorem Lorem Lorem LoremLorem
</div>
</div>
</div>
</div>
<div class='one-thirds'>
<div class="block square spec">
<div class="full image" style="background-image:url('http://lorempixel.com/300/300/sports/1/');"></div>
<div class="block-content full">
<h3>Title:</h3>
<div class="details-spec">
Lorem Lorem Lorem Lorem LoremLorem Lorem Lorem Lorem Lorem LoremLorem
</div>
</div>
</div>
</div>
<div class='one-thirds last'>
<div class="block square spec">
<div class="full image" style="background-image:url('http://lorempixel.com/300/300/sports/3/');"></div>
<div class="block-content full">
<h3>Title:</h3>
<div class="details-spec">
Lorem Lorem Lorem Lorem LoremLorem
</div>
</div>
</div>
</div>
</div>

You don't need that over complex jQuery. Set the styles with css and toggle a single class on the root element.
CSS
.spec.active .image {
display: none;
}
.spec.active .details-spec {
display: block;
}
.spec.active .block-content {
color: white;
}
JavaScript
var $spec = $('.spec');
$spec.click(function() {
$spec.not($(this)).removeClass('active');
$(this).toggleClass('active');
});
DEMO: http://codepen.io/anon/pen/VvpXXe

First close all ($spec). Second open current.($this)
var $spec = $(".spec").click(function() {
$spec.find(".image, .details-spec").show();
$spec.find(".block-content").removeClass('white');
$(this).find(".image, .details-spec").hide();
$(this).find(".block-content").addClass('white');
});

Related

Displaying a div inside a navbar with overflow-y: scroll

I'm trying to display a modal, the issue is the modal is inside a navbar which has the 'overflow-y' property set to 'scroll', which is making the value 'overflow-x' to 'auto', thus not allowing overflowing children on the x-asis, to be displayed. I'm looking for a way around this other than just moving the modal out of the navbar (It's not something that I can do for now). Is there a way via css to ignore the overflow-y property on the parent?
I made a fiddle with a similar case to the one I'm looking for: https://jsfiddle.net/aje31y7L/2/
<div class="background">
<nav class="navbar">
<div class="modal-wrapper">
<div class="modal-main">
</div>
</div>
</nav>
</div>
Currently the modal will appeared trimmed as part of it is hidden by the navbar. Any help is appreciated.
.background {
width: 100vw;
height: 100vh;
background-color: red;
position: relative;
}
.navbar {
display: block;
width: 400px;
left: -400px;
top: 0;
position: relative;
background: black;
max-height: 100%;
overflow-y: scroll;
transform: translateX(400px);
min-height: 100%;
}
.modal-wrapper {
display: flex;
position: relative;
align-items: center;
justify-content: center;
}
.modal-main {
display: flex;
height: auto;
background-color: grey;
}
h1{
font-size: 100px;
}
<div class="background">
<p>
lorem<br>
ipsum<br>
</p>
<nav class="navbar">
<div class="modal-wrapper">
<div class="modal-main">
<h1>
Lorem Ipsuim lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum
</h1>
</div>
</div>
</nav>
</div>
I have modified the code a little bit. As you run the snippet you will be able to see some text written in the div navbar in "p" tags but as soon as you erase the text inside "p" tags the div will go back in the background. Now as for the modal is concerned, I have modified the code too. The black background in the modal will not be visible but all the text inside it will be visible. It won't be chopped like before.

How to show only one div at the time?

I've got three sections, inside of which there are two divs. Inside the first one I have a button and after clicking it I should have the next one opened. However, only one div should be visible at the time (so when you click the next one, previous one should be closed). And I've got this functionality, but after clicking on the button again - it doesn't close the corresponding div.
I set up an example of my problem on codepen:
https://codepen.io/hubertstrawa/pen/abOwWMJ
<section>
<div class="product">
<span class="btn">Show more</span>
<p>Lorem ipsum</p>
</div>
<div class="product-more displayNone">
Test
</div>
</section>
$('.btn').click(function(e) {
// only one div to be shown but can't be closed as well.
$('.product-more').each(function(i, v) {
$(this).removeClass('displayBlock');
$(this).addClass('displayNone');
})
if ($(e.target).parent().next().hasClass('displayNone')) {
$(e.target).parent().next().removeClass('displayNone');
$(e.target).parent().next().addClass('displayBlock');
} else {
$(e.target).parent().next().removeClass('displayBlock');
$(e.target).parent().next().addClass('displayNone');
}
});
Any ideas how can I make it work?
Thank you
Change a .is-open on a parent element.
<section class="product is-open"> <!-- is-open toggled by JS -->
<div class="product-more"></div> <!-- handle children styles using CSS -->
</section>
.product-more { display: none; } /* default */
.product.is-open .product-more { display: block; } /* when ancestor is .is-open*/
Use delegateTarget inside the .on() method to get back the .product delegator element
const $product = $('.product'); // Collect all current products
$product.on('click', '.btn', function(e) {
const $thisProd = $(e.delegateTarget); // The .product delegator
$product.not($thisProd).removeClass('is-open'); // Handle all (but not this)
$thisProd.toggleClass('is-open'); // Handle current
});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}
.product {
background-color: #ededed;
width: 400px;
margin: 0 auto;
margin-bottom: 1rem;
}
.product-title {
position: relative;
padding: 1rem;
}
.product .btn {
position: absolute;
bottom: 0;
right: 0;
padding: .7rem;
background-color: cyan;
cursor: pointer;
}
.product-more {
width: 100%;
padding: 1rem;
background-color: cyan;
display: none; /* by default */
}
.product.is-open .product-more {
display: block;
}
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
This is preferred, since it lets you change HTML and CSS, and not worry any more about JavaScript - whilst by using .prev(), .next() or .parent() (like the other answers suggest) JS is just waiting for you to change the markup - to break.
No need to traverse back and forth your selectors.
No need for .displayNone and .displayBlock on the product-more element.
Handling dynamic .product
if your .product are dynamic elements, here's another solution to the above concept:
$('.allProducts').on('click', '.btn', function(e) {
const $product = $(e.delegateTarget).find('.product'); // Get all .product
const $thisProd = $(this).closest('.product'); // The closest .product ancestor
$product.not($thisProd).removeClass('is-open'); // Handle all (but not this)
$thisProd.toggleClass('is-open'); // Handle current
});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}
.product {
background-color: #ededed;
width: 400px;
margin: 0 auto;
margin-bottom: 1rem;
}
.product-title {
position: relative;
padding: 1rem;
}
.product .btn {
position: absolute;
bottom: 0;
right: 0;
padding: .7rem;
background-color: cyan;
cursor: pointer;
}
.product-more {
width: 100%;
padding: 1rem;
background-color: cyan;
display: none; /* by default */
}
.product.is-open .product-more {
display: block;
}
<div class="allProducts">
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
<section class="product">
<div class="product-title">
<p>Lorem ipsum</p>
<span class="btn">Show more</span>
</div>
<div class="product-more">Test</div>
</section>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
You can use the toggleClass it will detect your class and change it to another.
In your each function you just need to set all items to be hide and then it will toggle classes for current item.
Codepen
https://codepen.io/nasser-ali-karimi/pen/rNVwwLy?editors=1010
$('.btn').click(function(e) {
// only one div to be shown but can't be closed as well.
$('.product-more').each(function(i, v) {
$(this).removeClass('displayBlock');
$(this).addClass('displayNone');
})
$(e.target).parent().next().toggleClass('displayNone displayBlock');
});
A shorter version using jQuery would be using hide() and toggle():
$('.btn').click(function(e) {
var more = $(e.target).parent().next() ;
$('.product-more').not(more).hide();
$(e.target).parent().next().toggle();
});
You are hiding all the product-more sections when clicking any btn button, and then, trying to show/hide the product-more section associated with the clicked button.
So, when the section product-more is already shown and you click its btn button what happens is that you first hide the associated section and then your code checks if it is not visible and then shows its again.
One possible solution is to discard the associated product-more section when hiding. Also, as divs are shown by default, you don't need the displayBlock class.
$('.btn').click(function(e) {
var $current = $(e.target).parent().next('.product-more');
// Hide all sections that are not the one associated to the current button.
$('.product-more').not($current).addClass('displayNone');
// Show or hide current section.
$current.toggleClass('displayNone');
});

Replace css background-image: url(...) with <img> tag and keep scrolling over effect

I want to add alt tags to images on my website to improve SEO. The problem is I'm embedding them using CSS background-image: url(...).
It creates the desired scrolling effects (see below), but is not good for SEO.
Current code:
.text {
margin: 200px 20px;
}
.image-background {
background-attachment: fixed;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: 100%;
display: block;
height: 800px;
margin-bottom: 150px;
margin-left: -1500px;
margin-right: -1500px;
margin-top: 150px;
width: 3500px;
}
.image1 {
background-image: url(https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg);
}
.image2 {
background-image: url(http://media1.santabanta.com/full1/Animals/Cats/cats-149a.jpg);
}
<div class='text'>
Lorem ipsum dolores...
</div>
<div class='image-background image1'></div>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class='image-background image2'></div>
<div class='text'>
Lorem ipsum dolores...
</div>
The question is: how do I add <img> tags with alt properties without breaking the visual appearance?
Edit:
I tried using <img> with css position:fixed but can't get it to work well with more than one image (my broken jsfiddle here).
Edit 2:
These images are part of website content, not layout. They deserve alt tags, I'm not trying to stuff more keywords in a "bad" way. I originally put them as backgrounds to achieve a visual effect. Now I want to fix the mistake, but without changing how the website looks like.
I'm talking about my photos on this blog.
Edit 3:
I'm not trying to use only CSS here. Any code modification, JS library or pretty much anything is fine!
Method 1
This method doesn't change the visibility of the images, so I think there's no issues about SEO at all. But it is more complex and have the caveat that only one image can appear per once. So the text's div must to fill the entire screen resulting in a big padding.
$(function(){
var texts = $('.text');
var oldY = 0;
$(document).scroll(function(){
var y = window.scrollY;
texts.each(function(){
var text = $(this);
if(y >= text.offset().top)
text.next().addClass('active');
else
text.next().removeClass('active');
});
});
});
body{
padding: 0;
margin: 0;
}
.text{
padding: 20px;
margin: 0 0 600px;
position: relative;
z-index: 3;
background-color: #fff;
min-height: 100vh;
display: flex;
align-items: center;
}
.background-img img{
position: fixed;
top: 0;
left: 0;
z-index: 1;
width: 100%;
}
.background-img.active img{
z-index: 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img active">
<img src="https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg" alt="Image 1">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img">
<img src="http://media1.santabanta.com/full1/Animals/Cats/cats-149a.jpg" class="background-img" alt="Image 2">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>
Method 2
This is simpler, and to say the truth it's almost the same idea from your original code. The difference is that as soon as the page loads, the images are hidden and then copied as background images for their parent divs. The advantage is that you can have more then one image visible at the same time, which is a better effect.
$(function(){
$('.background-img img').each(function(){
var img = $(this).hide();
img.parent().css('background-image', 'url(' + img.prop('src') + ')');
});
});
body{
padding: 0;
margin: 0;
}
.text{
padding: 200px 20px;
position: relative;
z-index: 3;
background-color: #fff;
}
.background-img{
height: 400px;
background-attachment: fixed;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img">
<img src="https://i.ytimg.com/vi/tntOCGkgt98/maxresdefault.jpg" alt="Image 1">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>
<div class="background-img">
<img src="http://media1.santabanta.com/full1/Animals/Cats/cats-149a.jpg" class="background-img" alt="Image 2">
</div>
<div class='text'>
Lorem ipsum dolores...
</div>

HTML/CSS - How to place left and right divs outside container?

I'm developing a site built with Ribosome theme. What I would like are 3 divs outside the main container which has a responsive width, but I'm not sure how to get this done properly.
I want it to look something like this
I accomplished the above image by creating an invisible div between the left and right divs, that pushes them to the sides. I feel like this is a bad way to do it as it requires JavaScript or CSS to set the right width of the invisible div between them. The top div is placed inside the container, so it uses its width. This was the code:
<div class="outside-mid" style="background-color:#333;width:100%;height:300px;">Lorem ipsum dolor sit amet.</div>
<div id="outside-container" style="position:absolute;text-align:center;height:0;width:1144px;">
<div class="outside-left" style="background-color:#333;width:300px;height:600px;float:left;margin-left:-310px;">Lorem ipsum dolor sit amet.</div>
<div class="outside-right" style="background-color:#333;width:300px;height:600px;float:right;margin-right:-310px;">Lorem ipsum dolor sit amet.</div>
</div>
I set the width of outside-container using JS:
<script>
var width = document.getElementById('main').offsetWidth;
document.getElementById("outside-container").style.width = width + "px";
</script>
What I'm asking is if there's a way to just put the left and right divs inside the container and then, without using any invisible div to push them, just float them to the left and to the right outside the container. This way it would end up being responsive as it would always use the container width.
Set your html to look like this..
<div id="outside-container">
<div class="outside-left"></div>
<div class="main-div"></div>
<div class="outside-right"></div>
</div>
and try this css..
#outside-container { width: 100%; }
.outside-left { width: 20%; float: left; }
.outside-right { width: 20%; float: right; }
.main-div { width: 60%; float: left; }
please you can use this code.
Lorem ipsum dolor sit amet.
<div id="outside-container" style=" background: rgba(0, 0, 0, 0.5) none repeat scroll 0 0;display: table; height: 0; margin: 0 auto; text-align: center; width: 1144px;">
<div class="outside-left" style=" background-color: #333333;float: left; height: 600px; transform: translateX(-100%); width: 300px;">Lorem ipsum dolor sit amet.</div>
<div class="outside-right" style="background-color: #333333; display: inline-block; float: right; height: 600px; margin: 0 auto; transform: translateX(100%); width: 300px;">Lorem ipsum dolor sit amet.</div>
</div>
A lot of good answers here, but I found them quite hard to implement with the use of the same theme I already had installed. After looking through more solutions I found a way that worked for my case. I put the following inside the container, and it worked without altering the current layout.
<style>
#left:before, #right:before, #top:before {
position:absolute;
content: "Ads";
top:-20px;
color: #fff;
}
#left:before {
right:0;
}
.site {
overflow:visible;
position:relative;
top:340px;
}
</style>
<div id="top" style="position: absolute; width:100%; height:300px; top:0; background-color:#888;margin-top:-310px;"></div>
<div id="left" style="position: absolute; width:300px; height:600px; left: 0; top: 0; background-color:#888;margin-left:-310px;"></div>
<div id="right" style="position: absolute; width:300px; height:600px; right: 0; top: 0; background-color:#888;margin-right:-310px;"></div>
Note: .site refers to the parent (container)

Make Text appears (Slide up) under an Image when you click on it

I want a text description to appear (slide up) under an image when you click on it, and hidden(slid down) again when you when you click on it when already showing.
JAVASCRIPT
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.0/jquery-ui.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#image img").click(function () {
$("#image span").slideToggle();
});
});
</script>
CSS
#images {
width: 275px;
height: 200px;
}
#image div {
display: block;
width: 275px;
height: 200px;
}
#image img {
display: block;
width: 275px;
height: 200px;
}
#image span {
background: #000;
color: #ccc;
display: block;
width: 265px;
height: 40px;
padding: 5px;
display: none;
}
HTML
<div id="images">
<div id="image">
<div>
<img src="images/test-image.png" width="224px" height="224px" />
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
</div>
</div>
</div>
Those are the HTML above for the code I am trying to create, an example of this effect can be demonstrated when you click on any of the images on the site etchapps.com., any ideas how we can do this with JavaScript or jQuery. Or is there any other plugin that we could use to complete this.
The real trick for this effect is to make the containing wrapper position: relative, then the wrapper inside that position: absolute with top/right/bottom set at 0. That will anchor it to the bottom of the container regardless of the height of the caption when it's visible.
Then all you need to do is slideToggle the display of the caption element. At my work we just toggled a class and used CSS transitions to cover the display, but I've tweaked our method to fall inline with your code.
Here's a codepen example
HTML
<div id="images">
<div id="image">
<div>
<img src="http://placekitten.com/275/200" />
<div id="caption">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
</div>
</div>
CSS
#images {
width: 275px;
height: 200px;
}
#image {
position: relative;
width: 275px;
height: 200px;
overflow: hidden;
}
#image > div {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
#image img {
display: block;
width: 275px;
height: 200px;
}
#caption {
background: #000;
color: #ccc;
display: none;
overflow: hidden;
}
#caption p {
padding: 5px;
margin: 0;
}
JS
$(document).ready(function () {
$("#image img").click(function () {
$("#caption").slideToggle();
});
});
I'd also recommend switching from the divs to a figcaption and caption element for more semantic markup and probably switching out the ids for classes. You might need to update the JS to target the nearest caption rather than just any caption though.
<div id="images">
<div>
<div id="thetext" style="display:none">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<img id="theimage" src="images/test-image.png" width="224px" height="224px" />
</div>
</div>
</body>
<script>
$(document).ready(function () {
$("#theimage").click(function () {
$("#thetext").slideToggle();
});
});
</script>
Its solved:
Take a look at this fiddle: http://jsfiddle.net/promatik/SFU4E/
I changed a bit the HTML:
<div id="images">
<div id="image">
<div class="image">
<img src="images/test-image.png" width="275px" height="200px" />
</div>
<div class="text">
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
</div>
</div>
</div>
And CSS too:
#images, #image .image {
width: 275px;
height: 200px;
}
#image .text {
display: none;
background: #000;
}
#image span {
color: #ccc;
padding: 2px;
}

Categories