Allow one zoomed image at a time - css

I am using a fairly nice zoom-in / zoom-out effect using only CSS and HTML. The issue I am having is that if a user zooms in on two images, both images will be enlarged on the page. This is technically what it should do, however I am wondering how I can disable this effect.
This is what I am looking for: e.g. there are two images on a page. If I zoom in one one image and then zoom in on the other image (while the first image is zoomed), the first image should zoom out to allow the second image to be the only zoomed image on the page. This principle would apply if there were, for example, ten images -- only one image can be zoomed at any time.
input[type=checkbox] {
display: none;
}
.container img {
width: 100%;
transition: transform 0.25s ease;
cursor: zoom-in;
}
input[type=checkbox]:checked ~ label > img {
transform: scale(2.5);
cursor: zoom-out;
}
<div class="container">
<input type="checkbox" id="zoomCheck1">
<label for="zoomCheck1">
<img src="https://www.vintagevelo.co.uk/wp-content/uploads/2018/02/DSC_0040-768x512.jpg" />
</label>
</div>
<div class="container">
<input type="checkbox" id="zoomCheck2">
<label for="zoomCheck2">
<img src="https://premium-cycling.com/wp-content/uploads/2018/05/FAGGIN-Campione-del-mondo-1980s-frameset-7.jpg" />
</label>
</div>

Use the + single next selector instead of next all
Note: I recommend using more specific class selectors of some sort, so that these styles don't end up affecting other elements unintentionally, and make the styles more reusable.
Switched to radio elements to only allow one to be checked at a time. Use "name" to group them. You can also use name attribute for the selectors.
document.querySelector('.container').addEventListener('click', e => {
if (e.target.matches('input[type=radio] + label > img')) {
e.target.parentNode.previousSibling.previousSibling.checked = !e.target.parentNode.previousSibling.previousSibling.checked;
e.preventDefault();
}
});
input[type=radio] {
display: none;
}
.container img {
width: 100%;
transition: transform 0.25s ease;
cursor: zoom-in;
}
input[type=radio]:checked+label>img {
transform: scale(2.5);
cursor: zoom-out;
}
img {
width: 50px!important;
height: 50px;
}
<div class="container">
<input type="radio" name="zooms" id="zoomCheck1">
<label for="zoomCheck1">
<img class="center round-corner"
src="https://i.imgur.com/8qmxbHT.jpeg" />
</label>
<input type="radio" name="zooms" id="zoomCheck2">
<label for="zoomCheck2">
<img class="center round-corner"
src="https://i.imgur.com/8qmxbHT.jpeg" />
</label>
</div>

Related

How to add styling to another element when focus on another element (Different levels)?

I have a text field that I am trying to attach focus styling to and when focused, I want the box the expand and then include an "Add" button below the text area.
Both elements are on different levels (due to the existing structure of the code base). But I can't figure out how to hide/display the button when focusing on the text area. Here's an example of what I'm working with:
<form class='container'>
<div class='form-item'>
<div class='input-container>
<textarea id='addComment'></textarea>
</div>
</div>
<span class='button-wrapper'>
<button id='addCommentBtn'></button>
</span>
</form>
And here is the CSS/SCSS I've got
#addCommentBtn {
display: none;
}
#addComment {
transition: all 0.5s ease;
margin: 0.5em;
width: 95%;
}
#addComment:focus {
height: 10em;
margin-bottom: 2em;
}
#addComment:focus + #addCommentBtn {
display: block;
}
The expansion of the textarea on focus works as intended, but getting the button the change from display:none to display:block won't seem to work (I've tried a few different variations as well such as visibility).
If it comes down to it, I may have to adjust the Vue components, but this is last resort as it would require more tweaks/confirmation from project lead as the components are used in numerous areas and changes would affect those other areas as well.
ALSO: I would prefer not to use JQuery as well.
This should fix the problem. Flex will automatically adjust the height of container based on content.
function toggleButton(showFlag) {
document.getElementById('addCommentBtn').style.display = showFlag ? "inline" : "none";
}
.container {
display: flex;
flex-direction: column;
}
#addCommentBtn {
display: none;
}
<form class='container'>
<div class='form-item'>
<div class='input-container'>
<textarea id='addComment' onfocus="toggleButton(true)" onfocusout="toggleButton(false)"></textarea>
</div>
</div>
<span class='button-wrapper'>
<button id='addCommentBtn'>Add</button>
</span>
</form>

Flip animation not working on safari

I have a flip animation on my website. It works on every browser on PC and Android, but does not work on safari. It will flip and you see a flash of the "back" card and then it goes away and you just get a white square. I think I set the -webkit- like it is supposed to be set but for some reason it just isn't working. Does anyone have any ideas?
HTML:
<div class="card">
<div class="face front hover">
<img src="images/pawprints_edit.png" width="300" height="180" alt="sign up for al-van newsletter" id="news-img" class="d-inline-block col-md-12 img-fluid my-5 pt-2" />
<p id="thanks" class="text-center"></p>
</div>
<div class="face back">
<form name="mailForm" class="mail-form" autocomplete="on" novalidate>
<div class="form-group mb-0 px-2">
<label for="name">Name:</label>
<input type="text" class="form-control form-control-sm" id="name" placeholder="John Doe">
</div>
<div class="form-group mb-0 px-2">
<label for="email">Email Address:</label>
<input type="text" class="form-control form-control-sm" id="email" placeholder="yourname#domain.com">
</div>
<div class="form-group mb-0 px-2">
<label for="message">Please type your message:</label>
<textarea class="form-control form-control-sm" id="message" cols="30" rows="4"></textarea>
<input type="button" id="submit" value="Submit">
<input type="button" id="cancel" value="Cancel">
<p id="errorP" class="text-center"></p>
</div>
</form>
</div>
</div>
CSS:
/* form animation */
.scene {
width: 100%;
height: 300px!important;
perspective: 1000px;
-webkit-perspective: 1000px;
border: none;
}
.card {
width: 100%;
height: 100%;
position: relative;
-webkit-transition: -webkit-transform 1s;
transition: transform 1s;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
border: none;
}
.face {
position: absolute;
height: 100%;
width: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.front {
background: #98b98a;;
-webkit-z-index: -1;
z-index: -1
}
.front.hover {
background: #98b98a;
-webkit-z-index: 2;
z-index: 2;
}
.back {
background: #4c87a9;
-webkit-transform: rotateY(180deg);
transform: rotateY(180deg);
-webkit-z-index: 1;
z-index: 1;
}
.back [type=text]:hover {
cursor: text!important;
}
.card.is-flipped {
-webkit-transform: rotateY(180deg);
transform: rotateY(180deg);
}
.hover:hover {
cursor: pointer;
}
/* End animation */
and JS:
/* flip animation script */
function flip()
{
'use strict';
console.log("Flip is being triggered");
var card = document.querySelector(".card");
var face = document.querySelector(".front");
var name = document.getElementById("name");
var email = document.getElementById("email");
var errorP = document.getElementById("errorP");
if(card.removeEventListener)
{card.removeEventListener("click", flip, false);}
else if(card.detachEvent)
{card.detachEvent("onclick", flip);}
card.classList.toggle("is-flipped");
face.classList.toggle("hover");
name.style.background = "#fff";
email.style.background = "#fff";
errorP.style.display = "none";
}
/* Function to flip the card back over when canceled */
function cancelFlip()
{
'use strict';
console.log("Cancel has been activated");
var card = document.querySelector(".card");
var face = document.querySelector(".front");
card.classList.toggle("is-flipped");
face.classList.toggle("hover");
setTimeout(function(){if(card.addEventListener){card.addEventListener("click",flip,false);}else if(card.attachEvent){card.attachEvent("onclick",flip);}console.log("setTimeout was triggered");}, 500);
}
I am using a Boostrap 3 framework. JS is custom and CSS was taken from an online tutorial. The link to the site is: http://www.al-van.org/jake I'm developing on a windows platform and don't have an iPhone to test so I'm having my step-dad check it on his iPhone when I make changes. So far, nothing has been working.
UPDATE: it seems like the form is there, I'm able to click things and input text, but you cant actually see anything. It appears as a white square and nothing is visible. I moved the backface-visibility from .face to each .front and .back to see if that would make a difference. It seems it did not.
I found the issue. It seems that the .card class had a default background color which made the entire form white, washing out all of its components when flipped. When I removed this default background color and made it transparent. The issue was resolved.
add backface visibility to your class - .card.is-flipped, because you are using transform on that too

Is there a selector that handles "the element contains an element with class"

I have HTML like this:
<div class="form-group">
<input type="email" class="form-control>
<div class="form-error">This is not valid email address</div>
</div>
I am printing div.form-error dynamically if the input has errors.
I need CSS code to make the input's border red if there is a div.form-error in the div.form-group.
I'am working with SASS, maybe it has a function to do this. I'm looking for a something like this:
.form-group {
&:contains('.form-error') {
input {
border: 1px solid red;
}
}
}
How can I do it?
Okay, so while my comment still stands – it is not possible to use CSS to style a previous sibling, or ancestor, based on a subsequent sibling or descendant – there is a way around it. Though it while it does require a change of your HTML it will still emulate the element-order that you posted in your question.
That said, the HTML is changed from the following:
<div class="form-group">
<input type="email" class="form-control" />
<div class="form-error">This is not valid email address</div>
</div>
To:
<div class="form-group">
<div class="form-error">This is not valid email address</div>
<input type="email" class="form-control" />
</div>
.form-group {
/* to use the flex layout model: */
display: flex;
/* to have the elements arranged
in a column instead of a row
(which you may or may not want): */
flex-direction: column;
/* aesthetics, adjust to taste: */
width: 50%;
border: 1px solid #000;
margin: 0 0 0.5em 0;
}
.form-group .form-error {
/* places the .form-error element(s)
at the end of the layout in position
2, which causes the <input> to take
position 1; note that the elements
are still in the same place for CSS
selection: */
order: 2;
}
/* This styles the email <input> element if
it follows the .form-error element: */
.form-error + input[type=email] {
border-color: red;
}
<div class="form-group">
<div class="form-error">This is not a valid email address</div>
<input type="email" class="form-control" />
</div>
Incidentally it's worth noting that according to caniuse.com, flexbox is available in all current browsers; though your users may not have updated their own browsers to the current (or previous) version as of writing.
There are, of course, other ways you can achieve this simply using the :invalid pseudo-class:
/* Selects any <input> element whose value is invalid: */
input:invalid {
border-color: red;
}
<div class="form-group">
<input type="email" class="form-control" />
<div class="form-error">This is not a valid email address</div>
</div>
And, of course, you can even use fading to show or hide the error message:
/* Selects any <input> element whose value is invalid: */
input:invalid {
border-color: red;
}
/* hides the .form-error element using the opacity
property which takes a value, which allows it
to be animated from hidden (opacity: 0) to shown
(opacity: 1): */
.form-error {
/* visually hidden: */
opacity: 0;
/* specifies that the opacity property should be
transitioned over a 0.3 second time in a linear
animation: */
transition: opacity 0.3s linear;
}
/* Selects the .form-error element that immediately
follows an <input> which is :invalid */
input:invalid+.form-error {
opacity: 1;
}
<div class="form-group">
<input type="email" class="form-control" />
<div class="form-error">This is not a valid email address</div>
</div>
Bibliography:
"Using CSS Flexible Boxes."
You can use child selectors and sibling selectors.
For your example:
.form-group {
.form-error ~ input {
border: 1px solid red;
}
}
As pointed out correctly by folks in the comments, you will need to alter mark up for this to work. You can use the sibling selector:
https://developer.mozilla.org/en/docs/Web/CSS/Adjacent_sibling_selectors
.form-group {
.form-error + input {
border: 1px solid red;
}
}
.form-error + input {
border: 1px solid red;
}
<div class="form-group">
<div class="form-error">This is not valid email address</div>
<input type="email" class="form-control" />
</div>

Zoom in and out on mouse click with CSS

I want to zoom image with only CSS. The code below zooms the image when the left button of the mouse is kept pressed but I want to zoom in and out with a mouse click. How can I achieve that?
.container img {
transition: transform 0.25s ease;
cursor: zoom-in;
}
.container img:active {
-webkit-transform: scale(2);
transform: scale(2);
cursor: zoom-out;
}
Let's use a trick here, an input checkbox:
input[type=checkbox] {
display: none;
}
.container img {
margin: 100px;
transition: transform 0.25s ease;
cursor: zoom-in;
}
input[type=checkbox]:checked ~ label > img {
transform: scale(2);
cursor: zoom-out;
}
<div class="container">
<input type="checkbox" id="zoomCheck">
<label for="zoomCheck">
<img src="https://via.placeholder.com/200">
</label>
</div>
Building on #Nhan answer: https://stackoverflow.com/a/39859268/661872
Shorter, scoped and does not require tracking ids for multiple elements.
.click-zoom input[type=checkbox] {
display: none
}
.click-zoom img {
margin: 100px;
transition: transform 0.25s ease;
cursor: zoom-in
}
.click-zoom input[type=checkbox]:checked~img {
transform: scale(2);
cursor: zoom-out
}
<div class="click-zoom">
<label>
<input type="checkbox">
<img src="https://via.placeholder.com/200">
</label>
</div>
<div class="click-zoom">
<label>
<input type="checkbox">
<img src="https://via.placeholder.com/200">
</label>
</div>
4 Ways to Add Click Events with Only CSS Pseudo-Selectors
Note: I'll be using the word target when referring to the element we want to manipulate and trigger as the element we are using to manipulate target.
:checked
Use checkboxes or radios and :checked to determine or cause a target's state and/or to take action.
Trigger
<label>
<input type="checkbox">
<!--or-->
<input type="radio">
Conditions
Requires that the target must be:
A sibling that follows the trigger or...
...a descendant of the trigger.
Note
Hide the actual <checkbox> with display:none
Ensure that the <checkbox> has an id and that the <label> has a for attribute with a value matching the id of the <checkbox>
This is dependant upon the target being a sibling that follows the trigger or the target as a descendant. Therefore be aware that you'll most likely use these selector combinators: ~, +, >.
HTML
<label for='chx'>CHX</label>
<input id='chx' type="checkbox">
<div>TARGET</div>
CSS
#chx:checked + div {...
:target
Use an <a>nchor and apply the :target pseudo-selector on the target element.
Trigger
Conditions
Assign an id to the target.
Assign that same id to the <a> href attribute preceding with a hash #
HTML
<a href='#target'>A</a>
<div id='target'>TARGET</div>
CSS
#target:target {...
:focus
The trigger element must be either an <input> type or have the attribute tabindex in order to use :focus.
Trigger
<div tabindex='0'>ANY INPUT OR USE TABINDEX</div>
Conditions
Target must a sibling that is located after the trigger or *target must be a descendant of the trigger.
State or effect will persist until user clicks elsewhere thereafter a blur or unfocus event will occur.
HTML
<nav tabindex='0'>
<a href='#/'>TARGET</a>
<a href='#/'>TARGET</a>
<a href='#/'>TARGET</a>
</nav>
CSS
nav:focus ~ a {...
:active
This is a hack that cleverly exploits the transition-delay property in order to actually have a persistent state achieved with no script.
Trigger
<a href='#/'>A</a>
Conditions
Target must a sibling that is located after the trigger or *target must be a descendant of the trigger.
There must be a transition assigned to the target twice.
The first one to represent the persistent state.
The second one to represent the normal state.
HTML
A
<div class='target'>TARGET</div>
CSS
.target {
opacity: 1;
transition: all 0s 9999999s;
}
a:active ~ .target {
opacity: 0;
transition: all 0s;
}
Wacked looking, right? I'll try to explain it, but you're better off reading this article.
Under normal circumstances, if your trigger had the :active pseudo-selector, we are able to manipulate the target upon keydown. That means our active state is actually active as long as you keep your finger on the button...that's crappy and useless, I mean what are you expected to do to make .active to be useful? Maybe a paperweight and some rubber bands to keep a steady and persistent pressure on the button?
We will leave .active the way it is: lame and useless. Instead:
Make a ruleset for target under normal circumstances. In the example above it's opacity:1.
Next we add a transition: ...ok then... all which works, next is 0s ...ok so this transition isn't going to be seen it's duration is 0 seconds, and finally... 9999999s ...116 days delay?
We'll come back to that, we will continue onto the next rulesets...
These rulesets declare what happens to target under the influence of trigger:active. As you can see that it just does what it normally does, which is onkeydown target will become invisible in 0 seconds. Now once the user keys up, target is visible again...no *target's * new state of opacity:0 is persistent! No paperweight, technology has come a long way.
The target is still actually going to revert back to it's normal state, because :active is too lazy and feeble to work without rubber bands and paperweights. The persistent state is perceived and not real because target is still leaving the state brought on by :active which will be about 116 days before that will happen. ;)
This Snippet features the 4 ways previously mentioned. I'm aware that the OP requested zoom (which is featured therein), but thought it would be to repetitive and boring, so I added different effects as well as zooming.
SNIPPET
a {
text-decoration: none;
padding: 5px 10px;
border:1px solid red;
margin: 10px 0;
display: inline-block;
}
label {
cursor: pointer;
padding: 5px 10px;
border: 1px solid blue;
margin: 10px 0;
display:inline-block;
}
button {
cursor:pointer;
padding: 5px 10px;
border: grey;
font:inherit;
display:inline-block;
}
img#img {
width: 384px;
height: 384px;
display: block;
object-fit: contain;
margin: 10px auto;
transition: width 3s height 3s ease-in;
opacity: 1;
transition: opacity 1s 99999999s;
}
#zoomIn,
#zoomOut,
#spin {
display: none;
padding: 0 5px;
}
#zoomOut:checked + img#img {
width: 128px;
height: 128px;
transition: all 3s ease-out;
}
#zoomIn:checked + img#img {
width: 512px;
height: 512px;
transition: all 3s ease-in-out;
}
#spin:checked ~ img#img {
transform: rotate(1440deg);
}
img#img:target {
box-shadow: 0px 8px 6px 3px rgba(50, 50, 50, 0.75);
}
a.out:focus ~ img#img {
opacity: 0;
transition: opacity 1s;
}
a.in:active ~ img#img {
opacity: 1;
transition: opacity 1s;
}
.grey:focus ~ img#img {
filter: grayscale(100%);
}
<a href='#/' class='out'>FadeouT</a><a href='#/' class='in'>FadeiN</a>
<a href='#img'>ShadoW</a>
<br/><button class='grey' tabindex='0'>GreyscalE</button><br/>
<label for='spin'>SpiN</label>
<input type='checkbox' id='spin'>
<label for='zoomIn'>ZoomiN</label>
<input type='radio' id='zoomIn' name='zoom'>
<label for='zoomOut'>ZoomouT</label>
<input type='radio' id='zoomOut' name='zoom'>
<img id='img' src='https://i.ibb.co/5LPXSfn/Lenna-test-image.png'>
.container img {
margin: 100px;
transition: transform 0.25s ease;
cursor: zoom-in;
}
input[type=checkbox]:checked ~ label > img {
transform: scale(2);
cursor: zoom-out;
}
<div class="container">
<input type="checkbox" id="zoomCheck">
<label for="zoomCheck">
<img src="https://via.placeholder.com/200">
</label>
</div>
<html>
<head>
<title>Image Zoom</title>
<style type="text/css">
#imagediv {
margin:0 auto;
height:400px;
width:400px;
overflow:hidden;
}
img {
position: relative;
left: 50%;
top: 50%;
}
</style>
</head>
<body>
<input type="button" value ="-" onclick="zoom(0.9)"/>
<input type="button" value ="+" onclick="zoom(1.1)"/>
<div id="imagediv">
<img id="pic" src=""/>
</div>
<script type="text/javascript" language="javascript">
window.onload = function(){zoom(1)}
function zoom(zm) {
img=document.getElementById("pic")
wid=img.width
ht=img.height
img.style.width=(wid*zm)+"px"
img.style.height=(ht*zm)+"px"
img.style.marginLeft = -(img.width/2) + "px";
img.style.marginTop = -(img.height/2) + "px";
}
</script>
</body>
</html>

Overlapping a font awesome icon inside a text field

In an overlapping like the one below, how to prevent the large space between the title and text field?
.icon-link-mail {
position: relative;
left: 485px;
top: 29px;
padding: 8px 8px 7px 8px;
z-index: 2
}
<h3>Title</h3>
<form name="mail_form" id="mail_form" method="POST" action="">
<label for="sendto">
<i class="icon-envelope icon-2x icon-link-mail" style="color:#E4E4E4; text-decoration:none"></i>
<input name="sendto" class="sendto" type="text" style="width: 98%; margin-bottom:10px" placeholder="Send to.." />
</label>
</form>
Result can be seen in this fiddle
Personally I'd just use a pseudo-element, but if you wish to use the <i> icon, then we can do that a lot better by using position:absolute instead of position:relative. Adding position:relative just moves the icon, but leaves the space that it would have taken. position:absolute won't leave that space.
We need to make sure to set the parent contain (label) to position:relative though, so that the icon will be absolutely positioned in relation to the parent instead of the entire page.
#mail_form label {
position: relative;
}
.icon-link-mail {
position: absolute;
z-index: 2;
right: 0;
}
<h3>Title</h3>
<form name="mail_form" id="mail_form" method="POST" action="">
<label for="sendto">
<i class="icon-envelope icon-2x icon-link-mail" style="color:#E4E4E4; text-decoration:none"></i>
<input name="sendto" class="sendto" type="text" style="width: 98%; margin-bottom:10px" placeholder="Send to.." />
</label>
</form>
Result
Fiddle
http://jsfiddle.net/Ay6Hw/4/
I find the best way to do this is to just use an image. Here would be the code:
.search input {
padding-left: 17px;
background: #FFF url("../images/icon_search.png") left no-repeat;
}
.search input:focus {
background:#fff;
}
This will also remove the background image on focus giving the user a better experience overall.
Here is a solution that works with simple CSS and standard font awesome syntax, no need for unicode values, etc.
Create an <input> tag followed by a standard <i> tag with the icon you need.
Use relative positioning together with a higher layer order (z-index) and move the icon over and on top of the input field.
(Optional) You can make the icon active, to perhaps submit the data, via standard JS.
See the three code snippets below for the HTML / CSS / JS.
Or the same in JSFiddle here:
Example: http://jsfiddle.net/ethanpil/ws1g27y3/
$('#filtersubmit').click(function() {
alert('Searching for ' + $('#filter').val());
});
#filtersubmit {
position: relative;
z-index: 1;
left: -25px;
top: 1px;
color: #7B7B7B;
cursor: pointer;
width: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="filter" type="text" placeholder="Search" />
<i id="filtersubmit" class="fa fa-search"></i>

Resources