I am attempting to have a rollover effect have 1-3 different colors in Sass. How would I do this? Here's my code so far..
input[type=submit] {
font-size:1.3em;
padding:5px;
font-family:$paragraphFont;
width:400px;
border:1px solid #888;
box-sizing:border-box;
margin-top:15px;
cursor:pointer;
transition:background-color .2s ease-in-out;
&:hover {
cursor:pointer;
background-color:#3cde77;
}
}
<form>
<p>Name:</p><input type="text" />
<p>Email:</p><input type="text" />
<p>Message:</p><textarea></textarea>
<input type="submit" value =" Send Message" />
</form>
I image you could use the random() function somehow and assign my colors to a number but I don't know how.
Any thoughts guys?
What You can do is a random function of SCSS
$repeat: 10; // 10 iterations
input[type=submit]{
#for $i from 1 through $repeat{
&:nth-child(#{$i}) {
background-color: rgb(random(255),random(255),random(255));
}
}
}
I was able to do this using JS. It randomly picks from 3 different colors each time your hover over the Send Message button. It then reverts to an initial grey color.
var send = document.querySelector('.send');
send.addEventListener("mouseover", function() {
var colors3 = ["red", "green", "blue"];
var randomColor = colors3[Math.floor(Math.random() * 3)];
this.style.backgroundColor = randomColor;
});
send.addEventListener("mouseout", function() {
this.style.backgroundColor = "darkgrey";
});
input[type=submit] {
font-size: 1.3em;
padding: 5px;
font-family: $paragraphFont;
width: 400px;
border: 1px solid #888;
box-sizing: border-box;
margin-top: 15px;
cursor: pointer;
transition: background-color .2s ease-in-out;
background-color: darkgrey;
}
<form>
<p>Name:</p><input type="text" />
<p>Email:</p><input type="text" />
<p>Message:</p><textarea></textarea>
<input type="submit" class="send" value=" Send Message" />
</form>
http://codepen.io/anon/pen/ryowjZ
This is not a complete solution, and I'm sure it's not a good solution, but it is a pure CSS solution: http://codepen.io/anon/pen/oZJqxR
The idea is that you have your button constantly cycling background colors with a CSS keyframe animation, but hidden behind a mask. When you hover, the mask is removed and the animation is paused, giving you a 'frozen' color that is picked based on where the cycle is when your mouse enters the button.
HTML:
<button><span>Hover me</span></button>
The CSS
button {
padding: 0.5rem 2rem;
border: 1px solid #CCC;
font-size: 1.5rem;
background: pink;
position: relative;
-webkit-animation: cycle 1s steps(3) infinite;
animation: cycle 1s steps(3) infinite;
}
button:after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #DDD;
}
button span {
position: relative;
z-index: 1;
}
button:hover {
-webkit-animation-play-state: paused;
animation-play-state: paused;
}
button:hover:after {
display: none;
}
#keyframes cycle {
50% {
background: blue;
}
100% {
background: green;
}
}
This currently isn't picking cleanly between the 3 stated colors - some intermediate colors are shown. This is down to the keyframe animation and the steps declaration on the button - I'm sure it can be done, but it requires fine-tuning.
Last caveat - this is way more resource intensive than just picking a colour with javascript - it would get very heavy if you had more than a couple of these elements on a page at once.
Related
I have a dropdown menu appearing on button click. The problem is, the dropdown menus is appearing with animation all time without problem on PC, but plays with animation only once (on first click only) on mobile browsers.
function myFunction() {
var x = document.getElementById("dropdown");
if (x.className.indexOf("w3-show") == -1) {
x.classList.add("w3-show");
} else {
x.classList.remove("w3-show");
}
}
#dropdown { display:none;
border-radius: .25em;
box-shadow: 0.1em 0.1em 0.5em rgba(0,0,0,1);
background-color: rgba(0,0,0,0.3);
padding: 5px;
font-size: 22px;
color: white;
position: relative;
/* width:fit-content; */
width: 250px;
right: 0;
left: -25px;
margin: auto;}
.w3-show {
position: relative;
display: block!important;
}
.w3-animate-zoom {
animation:animatezoom 0.6s;
-webkit-animation: animatezoom 0.6s;
}
#keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
<button onclick="myFunction()" class="ikincibaslik" id="buttonme">Open dropdown menu</button>
<div id="dropdown" class="show-on-scroll w3-animate-zoom" >
First item
Second item
</div>
Any ideas?
I've got it working by making the following changes:
indexOf is for arrays, you want to use the event listener and classlisttoggle instead: How do I use vanilla JavaScript to write a toggle function I wrote in JQuery?
I updated the variables (this is a style thing, not an error)
I updated the CSS class to account for the w3-show class being added to the dropdown id, and I added a display none for the dropdown id
I removed the onclick from the button and used the id instead (style thing) and removed the space for the added and removed w3-show class
Edit: Hat tip to this post: keyframe animation does not work on safari for iOS the idea is to call a separate keyframe for each browser prefix so I've added a webkit-specific one, and I realised the original animatezoom didn't have a close } bracket.
It works now:
var myButton = document.getElementById("buttonme");
var dropDown = document.getElementById("dropdown");
myButton.addEventListener("click", ()=>{
dropDown.classList.toggle("w3-show");
});
#dropdown {
display:none;
border-radius: .25em;
box-shadow: 0.1em 0.1em 0.5em rgba(0,0,0,1);
background-color: rgba(0,0,0,0.3);
padding: 5px;
font-size: 22px;
color: white;
position: relative;
/* width:fit-content; */
width: 250px;
right: 0;
left: -25px;
margin: auto;}
#dropdown.w3-show {
position: relative;
display: block;
}
.w3-animate-zoom {
animation:animatezoom 0.6s;
-webkit-animation: animatezoom 0.6s;
}
#keyframes animatezoom{
from{transform:scale(0)
}
to
{transform:scale(1)}
}
}
#-webkit-keyframes animatezoom {
from{transform:scale(0)
}
to
{transform:scale(1)}
}
}
<button class="ikincibaslik" id="buttonme">Open dropdown menu</button>
<div id="dropdown" class="show-on-scroll w3-animate-zoom" >
First item
Second item
</div>
I need to change width of the element on two different events and with different speeds. Can I somehow specify two transitions of the same property or do I have to change approach?
Let's say I want to quickly increase width of a box with hover. And be able to do the same thing with a button but slower. The problem here is when the class is removed from the box so is the 3s transition. I want a 3s transition to last for the shrinking of the box after the button is pushed again.
const box = document.getElementById("box");
function growQuickly(){
box.classList.toggle("grow");
}
.box{
height:100px;
width:100px;
background: red;
transition: .5s;
}
.box.grow{
width: 200px;
transition: 3s;
}
.box:hover{
width:200px;
}
<div class="box" id="box" ></div>
<button onclick="growQuickly()">GROW SLOWLY</button>
You can separate your logic into more classes and check if something is already included using js.
CSS
.box {
height: 100px;
width: 100px;
background: red;
transition-duration: 0.5s;
}
.box:hover {
width: 200px;
}
.wide {
width: 200px;
}
.slow {
transition-duration: 3s;
}
JS
const box = document.getElementById('box');
function growQuickly() {
const boxWidth = box.offsetWidth;
if (boxWidth === 200 && box.classList.contains('slow')) {
box.classList.toggle('wide');
setTimeout(() => box.classList.toggle('slow'), box.style.transitionDuration);
} else {
box.classList.toggle('wide');
box.classList.toggle('slow');
}
}
The demo is quite simple, and similar to the example in the Vue.js docs.
new Vue({
el: '#demo',
data: {
show: true
}
})
p {
width: 100px;
border: 1px solid red;
}
.fade-enter-active,
.fade-leave-active {
transition: all 5s;
}
.fade-enter {
opacity: 0;
width: 500px;
background: red;
}
.fade-enter-to {
background: black
}
.fade-leave {
opacity: 0;
background: red
}
.fade-leave-to {
background: black;
width: 1000px;
opacity: 1
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
The question is, when the leave animation begins, it seems it's removed from the DOM (v-if is false) so quickly that there isn't any animation at all!
But, if I remove opacity, the animation works! Why does opacity matter?
.fade-leave {
/* opacity: 0; */
background: red;
}
.fade-leave-to {
background: black;
width: 1000px;
/* opacity:1; */
}
There is another question, I thought the leave animation should be that the DOM background becomes red firstly (while the result is it didn't or I just can't tell), then change to black slowly. So, is it my misconception?
The opacity is important because the animation is fading according to it.
Here I have added to opacity of 0 directly to the class fade-enter-active of the button Hello. You can see the animation fading step by step.
Instead, with an opacity of 1, there is no direction to your fading. It stays at 1.
I want to make
background-color: green;
border: 5px solid green;
for a button only for 0.5 seconds effect after a click, to animate a click. How can I do it?
You'll need to use some JavaScript to detect the click and change change the styles. You could possibly make do with a CSS animation, but you'd still need JavaScript to trigger it, so I'm not sure it's worth the effort to make it work in CSS anyways:
function setStyles(el, styles) {
Object.entries(styles).map(
([property, value]) => el.style[property] = value
)
}
const btn = document.querySelector("button")
btn.addEventListener("click", () => {
// capture original styles
const origStyles = {
background: btn.style.background,
border: btn.style.border,
}
// set temp styles
setStyles(btn, {
background: "green",
border: "5px solid green",
})
// reset original styles after 0.5 seconds
window.setTimeout(() => setStyles(btn, origStyles), 500)
})
<button>Click Me</button>
.foo-button {
/* Disable OS styling */
appearance: none;
border: none;
/* Rounded corners */
border-radius: 4px;
/* Text padding */
padding: 6px 12px;
/* Normal color */
background: #2442a0;
/* Text style */
color: white;
text-shadow: 0 0 1px rgba(0, 0, 0, .3);
/* Animation (“transition” timing) */
transition: .5s background;
}
.foo-button:active {
animation-duration: .5s;
animation-name: blink;
animation-fill-mode: forwards;
animation-iteration-count: 1;
background: green;
}
#keyframes blink {
0% {
background: green;
}
100% {
background: #2442a0;
}
}
<button class="foo-button">Button Text</button>
I have a blockquote like this:
<blockquote class="spoiler">Soopah sekkrit!</blockquote>
I want to make it hidden, only showing it if the user hovers over it. I'm doing it now with JS:
blockquote.addEventListener('mouseover', function() {
this.style.height = this.offsetHeight + 'px';
this.dataset.contents = this.innerHTML;
this.innerHTML = '';
});
blockquote.addEventListener('mouseout', function() {
this.style.height = '';
this.innerHTML = this.dataset.contents;
});
Is there a better way to do this, with CSS?
It has to keep its background-color, size, and work for contents with custom colors. If possible, I'd also like to animate it so the contents fade in gradually.
Here's something very similar to what I use in SOUP:
.spoiler, .spoiler > * { transition: color 0.5s, opacity 0.5s }
.spoiler:not(:hover) { color: transparent }
.spoiler:not(:hover) > * { opacity: 0 }
/* fix weird transitions on Chrome: */
blockquote, blockquote > *:not(a) { color: black }
.spoiler, .spoiler > * { transition: color 0.5s, opacity 0.5s }
.spoiler:not(:hover) { color: transparent }
.spoiler:not(:hover) > * { opacity: 0 }
/* fix weird transitions on Chrome: */
blockquote, blockquote > *:not(a) { color: black }
/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<blockquote class="spoiler">
Soopah sekkrit text with <code>code</code> and links and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
<p>You can also have paragraphs in here.</p>
<ul><li>And lists too!</li></ul>
<blockquote class="spoiler">Even nested spoilers work!</blockquote>
</blockquote>
This is somewhat simpler than your own solution, and works for arbitrary content including images and even nested spoilers! (See demo snippet above.)
Alas, this method seems to suffer from weird transition effects on Chrome if any of the child elements of the spoiler have color: inherit. (Basically, what's happening is that these elements will have both their text color set to transparent and their opacity set to 0. Because opacities combine multiplicatively, the combined transition will thus appear slower — halfway through the fade-in, when the element itself is at 50% opacity, the text in it is at 50% × 50% = 25% opacity.) I've added an extra CSS rule to the example above to fix this, but it does make things a bit complicated.
What I actually do in SOUP is slightly different. I wrap the contents of each spoiler in an extra inner <div>, which lets me simplify the CSS further to just:
.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }
.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }
/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<blockquote class="spoiler"><div>
Soopah sekkrit text with <code>code</code> and links and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
<p>You can also have paragraphs in here.</p>
<ul><li>And lists too!</li></ul>
<blockquote class="spoiler"><div>Even nested spoilers work!</div></blockquote>
<div></blockquote>
The main advantages of this method are simplicity and robustness: I don't have to use :not() selectors, improving compatibility with older browsers, and the transition styles can't conflict with other transitions possibly defined on the elements inside the spoiler. This method also doesn't suffer from the color transition weirdness on Chrome described above, since it only uses opacity transitions.
Overall, this is the method I recommend. The disadvantage, of course, is that you need to include the extra <div>s in your HTML.
Ps. Please consider also providing some way to make the spoilers permanently visible, especially for touch screen users who may find it very hard to "hover" the cursor over an element. A simple solution is to use a JavaScript click event handler to toggle the spoiler class, e.g. like this (using jQuery):
$('.spoiler').on( 'click', function (e) {
$(this).toggleClass('spoiler');
e.stopPropagation();
} );
$('.spoiler').on( 'click', function (e) {
$(this).toggleClass('spoiler');
e.stopPropagation();
} );
.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }
/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<blockquote class="spoiler"><div>
Soopah sekkrit text with <code>code</code> and links and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
<p>You can also have paragraphs in here.</p>
<ul><li>And lists too!</li></ul>
<blockquote class="spoiler"><div>Even nested spoilers work!</div></blockquote>
<div></blockquote>
or, if you'd prefer to use delegated event handling (so that you don't have to keep adding new click handlers every time you load new content that includes spoilers via Ajax):
$(document).on( 'click', '.spoiler, .spoiler-off', function (e) {
$(this).toggleClass('spoiler').toggleClass('spoiler-off');
e.stopPropagation();
} );
$(document).on( 'click', '.spoiler, .spoiler-off', function (e) {
$(this).toggleClass('spoiler').toggleClass('spoiler-off');
e.stopPropagation();
} );
.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }
/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<blockquote class="spoiler"><div>
Soopah sekkrit text with <code>code</code> and links and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
<p>You can also have paragraphs in here.</p>
<ul><li>And lists too!</li></ul>
<blockquote class="spoiler"><div>Even nested spoilers work!</div></blockquote>
<div></blockquote>
(These should work with either of the CSS variants shown above.)
Yes, this is possible with CSS. Essentially, you want to make all of the contents be invisible. In CSS, this means transparent.
First use the hover pseudo-class inside the not pseudo-class:
.spoiler:not(:hover)
But we also need to select all the child elements of the hovered spoiler, to set their colors and backgrounds:
.spoiler:not(:hover) *
And we set both the color and background (only for the child elements) to transparent to make them invisible to the user. All together:
.spoiler:not(:hover), .spoiler:not(:hover) * { color: transparent }
.spoiler:not(:hover) * { background: transparent }
code { padding: 2px; background: #bbb }
a { color: #00f }
Hover: <blockquote class="spoiler">Some stuff <a>and a colored link</a> <code>and some code!</code></blockquote>
We can also add a transition to make it smoother:
.spoiler { transition: color 0.5s } /* we have to put this outside the :hover to make it work fading both in and out */
.spoiler:not(:hover), .spoiler:not(:hover) * { color: transparent }
.spoiler * { transition: color 0.5s, background 0.5s }
.spoiler:not(:hover) * { background: transparent }
code { padding: 2px; background: #bbb; color: #000 } /* add color to prevent double transition */
a { color: #00f }
Hover: <blockquote class="spoiler">Some stuff <a>and a colored link</a> <code>and some code!</code></blockquote>
To make it obvious to the user that the blockquote is hoverable, you can add some text with the ::after pseudo-element to be shown when the blockquote isn't hovered:
.spoiler { transition: color 0.5s; position: relative } /* relative position for positioning the pseudo-element */
.spoiler:not(:hover), .spoiler:not(:hover) * { color: transparent }
.spoiler * { transition: color 0.5s, background 0.5s }
.spoiler:not(:hover) * { background: transparent }
.spoiler::after {
content: 'hover to view spoiler';
position: absolute;
top: 0; left: 0;
color: transparent;
}
.spoiler:not(:hover)::after {
color: #666;
transition: color 0.3s 0.3s; /* delayed transition to keep the text from overlapping */
}
code { padding: 2px; background: #bbb; color: #000 }
a { color: #00f }
<blockquote class="spoiler">
Some stuff <a>and a colored link</a> <code>and some code!</code>
<blockquote class="spoiler">Nesting bonus!</blockquote>
</blockquote>
For stuff like images, svgs (tho inline SVG can be very granularly controlled), canvases, and all that fancy stuff, instead of color you'd have to use opacity. We can make it work with these by adding this:
.spoiler img { transition: opacity 0.5s, background 0.5s }
.spoiler:not(:hover) img { opacity: 0 }
Here's a strategy that works pretty well, looks nice, and has pretty clean transitions
.spoiler {
position: relative;
display: inline-block;
cursor: help;
}
.spoiler::before {
content: 'psst\02026'; /* … */
position: absolute;
left: -2px;
top: -2px;
right: -2px;
bottom: -2px;
border-radius: 1px;
font-size: .9rem;
color: #e6578c;
background: #ffe5e5;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
opacity: 1;
transition: opacity 0.7s ease, transform 0.3s ease; /* hide faster than reveal */
}
.spoiler:hover::before {
opacity: 0;
transform: translateY(-50%)rotateX(80deg);
transition: opacity 1.0s ease, transform 0.5s ease; /* slower reveal */
}
If you style the parent block with opacity: 0 without hover, then you can't add any styles to illustrate what part of the page the user should be hovering over.
Instead, if we add a ::before element that covers up the child content, then we can fade it out on hover and still provide a visual indication of where to go.
Demo in Stack Snippets
.spoiler {
position: relative;
display: inline-block;
cursor: help;
}
.spoiler::before {
content: 'psst\02026'; /* … */
position: absolute;
left: -2px;
top: -2px;
right: -2px;
bottom: -2px;
border-radius: 1px;
font-size: .9rem;
color: #e6578c;
background: #ffe5e5;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
transition: opacity 0.7s ease, transform 0.3s ease; /* hide faster than reveal */
}
.spoiler:hover::before {
opacity: 0;
transform: translateY(-50%)rotateX(80deg);
transition: opacity 1.0s ease, transform 0.5s ease; /* slower reveal */
}
/* demo styles */
blockquote {
margin: 0
}
<p>
Inline Spoiler <span class="spoiler" > Word </span>
</p>
<p class="spoiler">
Paragraph Text Block of a Spoiler
</p>
<blockquote class="spoiler">
Block quote spoiler with super long text that wraps and wraps and wraps some more.
Block quote spoiler with super long text that wraps and wraps and wraps some more.
Block quote spoiler with super long text that wraps and wraps and wraps some more.
</blockquote>