Is it possible to change the CSS applied to an element specified with ::before?
For example:
I am wanting to change this piece of CSS
.wrapper {
position: relative;
z-index: 0;
display: inline-block;
background: #e5e5e5;
}
.wrapper::before {
position: absolute;
z-index: 1;
top: 0;
width: calc(100% - 15px);
height: 100%;
box-shadow: inset 0 10px 10px -1px rgba(0, 0, 0, 0.6);
pointer-events: none;
content: "";
}
such that the box-shadow is applied at a specific time via javascript in something resembling this process...
addShadow : function() {
var scroll = this.$.container.scrollTop;
if(scroll >= 2) {
this.$.wrapper.classList.add('shadow');
} else {
this.$.wrapper.classList.remove('shadow');
}
},
Feel free to edit my Fiddle and give me some feedback
As you are already toggling the .shadow class, all you need to do is alter the css selector:
.wrapper.shadow::before {
Related
I am trying to make a div element which when scrolled down will change properties drastically. Here is the codepen example of how I want it to work.
Instead of hover I want it so that when scrolled down, the page wide div will turn into that little circle div which when clicked will function as a back to the top button. It doesn't matter if more classes are added or anything of that sort. I am very new to js and I tried a few things and also googled about it, I got the scroll code from w3school's how to make a back to top button guide which specifies that when scrolled down by 20px the code would react, but I don't know how to turn the JavaScript to JS when scrolled down along with the transformation of the div.
Thanks in advance
I think you want to implement scroll to top functionality, very common these days in most of the web app.
You need to keep below things and design that feature.
There is one header, that should have a reference ID with hash to scroll back to top
Create a button that will always static position (JS) button, will show up when user scroll the window
Bind click event on the button that scroll back to top
Here is the you can see this implementation and use it.
.html
<h1 class="intro-copy">
Scroll down to use this simple back-to-top button made with modern vanilla javascript.
</h1>
<a class="top-link hide" href="" id="js-top">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6"><path d="M12 6H0l6-6z"/></svg>
<span class="screen-reader-text">Back to top</span>
</a>
.css
body {
height: 2000px;
position: relative;
}
.intro-copy {
padding: 1em;
margin: 50vh auto;
max-width: 15em;
font-family: Helvetica;
font-weight: lighter;
font-size: 2em;
line-height: 1.2;
text-align: center;
}
.top-link {
transition: all .25s ease-in-out;
position: fixed;
bottom: 0;
right: 0;
display: inline-flex;
cursor: pointer;
align-items: center;
justify-content: center;
margin: 0 3em 3em 0;
border-radius: 50%;
padding: .25em;
width: 80px;
height: 80px;
background-color: #F8F8F8;
&.show {
visibility: visible;
opacity: 1;
}
&.hide {
visibility: hidden;
opacity: 0;
}
svg {
fill: #000;
width: 24px;
height: 12px;
}
&:hover {
background-color: #E8E8E8;
svg {
fill: #000000;
}
}
}
// Text meant only for screen readers.
.screen-reader-text {
position: absolute;
clip-path: inset(50%);
margin: -1px;
border: 0;
padding: 0;
width: 1px;
height: 1px;
overflow: hidden;
word-wrap: normal !important;
clip: rect(1px, 1px, 1px, 1px);
&:focus {
display: block;
top: 5px;
left: 5px;
z-index: 100000; // Above WP toolbar
clip-path: none;
background-color: #eee;
padding: 15px 23px 14px;
width: auto;
height: auto;
text-decoration: none;
line-height: normal;
color: #444;
font-size: 1em;
clip: auto !important;
}
}
JS:
// Set a variable for our button element.
const scrollToTopButton = document.getElementById('js-top');
// Let's set up a function that shows our scroll-to-top button if we scroll beyond the height of the initial window.
const scrollFunc = () => {
// Get the current scroll value
let y = window.scrollY;
// If the scroll value is greater than the window height, let's add a class to the scroll-to-top button to show it!
if (y > 0) {
scrollToTopButton.className = "top-link show";
} else {
scrollToTopButton.className = "top-link hide";
}
};
window.addEventListener("scroll", scrollFunc);
const scrollToTop = () => {
// Let's set a variable for the number of pixels we are from the top of the document.
const c = document.documentElement.scrollTop || document.body.scrollTop;
// If that number is greater than 0, we'll scroll back to 0, or the top of the document.
// We'll also animate that scroll with requestAnimationFrame:
// https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
// ScrollTo takes an x and a y coordinate.
// Increase the '10' value to get a smoother/slower scroll!
window.scrollTo(0, c - c / 10);
}
};
// When the button is clicked, run our ScrolltoTop function above!
scrollToTopButton.onclick = function(e) {
e.preventDefault();
scrollToTop();
}
I need to target two div elements and toggle their classes simultanouesly.
I understand that I can get multiple divs "by ID" by using .querySelectorAll
but when I get to .classlist.toggle ("NewClassName"); how can I target two classes??
So here's some code:
#small-div{
background-color:#aaaaaa;
border: 3px solid #aaaaaa;
padding: 0px 0px 0px 0px;
margin: auto 10px auto auto;
border-radius: 10px;
overflow: auto;
}
.tobetoggled{
width: 45%;
float: left;
}
#small-div2{
background-color:#aaaaaa;
border: 3px solid #aaaaaa;
padding: 0px 0px 0px 0px;
margin: auto 10px auto auto;
border-radius: 10px;
overflow: auto;
}
.tobetoggled2{
width: 45%;
float: right;
}
.toggletothis{
width: 100%;
float: left;
position: fixed;
display: block;
z-index: 100;
}
.toggletothis2{
width: 100%;
float: left;
position: fixed;
display: block;
z-index: 100;
}
.whensmalldivistoggled{
display: none;
}/* when small-div is clicked, small-div toggles to class "tobetoggled" while small-div 2 simultaneously toggles to class "whensmalldivistoggled" (the display none class) */
<div id="container">
<div class="tobetoggled" onclick="function()" id="small-div">
</div>
<div class="tobetoggled2" onclick="separatefunction()" id="small-div2">
</div>
</div> <!-- end container -->
<script>
function picClicktwo() {
document.querySelectorAll("small-div, small-div2").classList.toggle("toggletothis, whensmalldivistoggled");
}
</script>
So as you can see one div is on the right, the other is on the left, each set to 45% width. So if I toggle one div to 100% width the browser still respects the other divs space instead of taking the whole 100%.
So I'm thinking if I can get the div on the right ,for example, to not display when the div on the left is toggled, it will be out of the way so the left div can take all 100%
Maybe im going about this the wrong way. Any help is welcome. Thanks.
You can create a single javascript function that sets appropriate classes on each element. Since you have only two elements it is not too complex.
HTML
<div id="container">
<div id="lefty" onclick="toggle('lefty', 'righty')">Lefty</div>
<div id="righty" onclick="toggle('righty', 'lefty')">Righty</div>
</div>
JS
function toggle(target, other)
{
var t = document.getElementById(target);
var o = document.getElementById(other);
if (!t.className || t.className == "inative")
{
t.className = "active";
o.className = "inactive";
}
else
{
t.className = "";
o.className = "";
}
}
CSS
#container {
background-color: lightgreen;
padding: 15px 0;
}
#container div {
color: white;
width: 45%;
display: inline-block;
}
#lefty {
background-color: blue;
}
#righty {
background-color: purple;
}
#container div.active {
width: 90%;
}
#container div.inactive {
display:none;
}
https://jsfiddle.net/dLbu9odf/1/
This could be made more elegant or capable of handling more elements with something like toggle(this) and then some DOM traversal and iteration in javascript, but that's a bit beyond scope. If that were the case I would recommend jQuery.
First of all, you can find a simplified demo of my code in this JSFiddle and also below the question. I found that my problem happens the way I describe it in Google Chrome, so if you plan to try and fix the bug, please use that browser. I apologize if the code is not very well simplified; please consider that this is a snippet from a bigger project.
I'm working on a webapp that uses JQuery and GreenSock's TweenLite for animations.
This app consists on some menus that control everything, that are transitioned between using the bodyChange() function. This function has two parameters:
nextOrPrev, that runs one animation or another based on the value
provided ("next" or "prev"). Only the "next" animation is done yet, but that is not important for now. The "prev" animation, not yet used, just emits an alert("prev").
bodyFunction. The function provided will fill the body with the elements necessary for that menu, and the wrap them in a #bodyWrap.
In the demo I provide you with there are only two menus: The first one, mainMenu, with only a #playButton. When you click it, the bodyChange() function is called with the following parameters: ("next", playSettingsBody), playSettings being the second menu.
This is the problem: when you click the playButton, the button goes up a on the screen and then executes the TweenLite animation. I can't see, however, why does the button "jump up", instead of staying in the same place and execute the animation. This is probably due to a small mistake. What is it?
Thanks for any help.
mainMenuBody();
function mainMenuBody() {
$("body").append(
//BUTTONS
"<div id='playButton' class='mainButton'><div class='buttonText mainButtonText text'>PLAY</div></div>"
);
//WRAP
$("body").wrapInner("<div id='bodyWrap'></div>");
//BINDS
$("#playButton").bind("click", function() {
bodyChange("next", playSettingsBody);
});
}
function bodyChange(nextOrPrev, bodyFunction) {
switch (nextOrPrev) {
case "next":
//ANIMATION AND BODY CHANGE
TweenLite.to($("#bodyWrap"), .4, {
ease: Power2.easeIn,
transform: "rotateY(90deg)",
onComplete: function(){
$("body").empty();
//NEW STUFF
bodyFunction();
TweenLite.from($("#bodyWrap"), .4, {
ease: Power2.easeOut,
transform: "rotateY(90deg)"
});
}
});
//END OF ANIMATION AND BODY CHANGE
break;
case "prev":
alert("prev");
}
}
function playSettingsBody() {
$("body").append(
"<p class='text' id='CYTText'>This is the second menu!</p>"
);
}
body{
background-image: url("../resources/pics/Vignette2.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
background-color: #02BFC1;
overflow:hidden;
margin: 0;
}
.text {
color: #FFFFFF;
font-family:Bebas Neue;
-webkit-user-select: none;
cursor: default;
text-shadow: 3px 3px 2px rgba(0,0,0,0.2);
}
.mainButton {
-webkit-transform:scale(1);
width: 200px;
height: 200px;
border: 10px solid #F1F2F0;
text-align:center;
background-color: #F37C2B;
/*background:#5F4A21;*/
display: table;
position: absolute;
margin: auto;
top: 150px;
bottom: 0;
-webkit-transition: all 0.5s ease;
cursor: pointer;
box-shadow: 0px 0px 30px rgba(0,0,0,0.4);
}
.mainButtonText {
position: relative;
display:table-cell;
vertical-align:middle;
-webkit-transform:scale(1);
font-size: 90px;
text-shadow: 4px 4px 2px rgba(0,0,0,0.2);
-webkit-transition: all 0.5s ease;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
This problem is caused in your .mainButton class. Your code looks a little like this.
.mainButton {
position: absolute;
top: 150px;
bottom: 0;
//rest
}
By removing the line bottom: 0; your JSFiddle now works as expected. However, if you remove the line top: 150px; instead and leave in the bottom: 0 the problem still occurs. Unfortunately, I cannot provide an explanation for this. It might be worth posting a question on the GSAP forums inquiring about why this occurs works when positioning using bottom but not when using top
Edit
Since you need bottom: 0 and I wasn't able to fix your code I wrote an example which works using Timeline, a GSAP plugin. You can see this JSFiddle or the code example below.
var tl = new TimelineMax();
tl.pause();
tl.fromTo($("#click"), 1, {rotationY: 0, ease: Power2.easeOut}, {rotationY: 90, transformOrigin:"right", ease: Power2.easeOut})
.set($("#click2"), {css:{display: "table"}}, "-=0.6")
.fromTo($("#click2"), 1, {rotationY: -90, ease: Power2.easeOut}, {rotationY: 0, transformOrigin:"left", ease: Power2.easeOut}, "-=0.6");
$("#click").click(function() {
tl.play();
});
$("#click2").click(function() {
tl.reverse();
});
* {
margin: 0;
padding: 0;
}
body {
background-image: url("../resources/pics/Vignette2.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
background-color: #02BFC1;
overflow: hidden;
}
div.one, div.two {
position: absolute;
bottom: 0;
height: 200px;
width: 200px;
background: #F37C2B;
text-align: center;
display: table;
cursor: pointer;
border: 10px solid #F1F2F0;
}
div.one .text, div.two .text {
position: relative;
display: table-cell;
vertical-align: middle;
color: #FFFFFF;
font-family: Bebas Neue;
font-size: 90px;
}
div.two {
display: none;
border-color: transparent;
background: none;
}
div.two .text {
font-size: 40px;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<div id="click" class="one">
<div class="text">
Play
</div>
</div>
<div id="click2" class="two">
<div class="text">
Second Menu
</div>
</div>
when I click on the main circle the surrounding 5 circles will get minimized completely( to 100% hide), but those are not minimizing completely. There is a small circle over the main circle after minimizing. How to completely minimize (hide) the tiny circle on top of the main circle after toggle close.
I have tried jQuery hide but it was hiding entire element,
Below is the jQuery code,
var nbOptions = 8;
var angleStart = -360;
// jquery rotate animation
function rotate(li,d) {
$({d:angleStart}).animate({d:d}, {
step: function(now) {
$(li)
.css({ transform: 'rotate('+now+'deg)' })
.find('label')
.css({ transform: 'rotate('+(-now)+'deg)' });
}, duration: 0
});
}
// show / hide the options
function toggleOptions(s) {
$(s).toggleClass('open');
var li = $(s).find('li');
var deg = $(s).hasClass('half') ? 180/(li.length-1) : 360/li.length;
for(var i=0; i<li.length; i++) {
var d = $(s).hasClass('half') ? (i*deg)-90 : i*deg;
$(s).hasClass('open') ? rotate(li[i],d) : rotate(li[i],angleStart);
}
}
$('.selector button').click(function(e) {
toggleOptions($(this).parent());
});
setTimeout(function() { toggleOptions('.selector'); }, 100);
http://jsfiddle.net/adzFe/2574/
You do need to remove the border and padding inside .selector.open li input + label but you can toggle on and off with another class.
.open1 {
padding: 6px;
border:1px solid #999;
}
Add this JS:
function toggleOptions(s) {
$(s).toggleClass('open');
var li = $(s).find('li');
li.find("label").toggleClass("open1"); // NEW
...
}
Fiddle: http://jsfiddle.net/adzFe/2576/
I agree, the mini circle is caused by extra padding at wrong class, I have moved the padding to the selector.open. Now it is not showing any mini circle.
.selector li input + label {
position: absolute;
left: 50%;
bottom: 120%;
width: 0;
height: 0;
margin-left: 0;
background: #fff;
border-radius: 50%;
text-align: center;
overflow: hidden;
cursor: pointer;
background:#eee;
transition: all 0.8s ease-in-out, color 0.1s, background 0.1s;
}
.selector li input + label img {
border-radius:50%;
}
.selector.open li input + label {
width: 90px;
height: 90px;
margin-left: -40px;
padding:6px;
border:1px solid #999;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.1);
}
.selector.open li input + label:hover {
border:1px solid #fff;
padding:6px;
background:#fff;
}
.mainimage{
width:100%;
height:100%;
border-radius:50%;
}
Working code
http://jsfiddle.net/adzFe/2577/
Looks like the problem is in your CSS .selector li input + label rule. You still have some padding and border width in this rule which is giving the circles some size. Change those 2 values to 0 and they should completely hide:
.selector li input + label {
position: absolute;
left: 50%;
bottom: 120%;
width: 0;
height: 0;
margin-left: 0;
background: #fff;
border-radius: 50%;
text-align: center;
overflow: hidden;
cursor: pointer;
border:0 solid #999; /* previously 1px */
padding:0; /* previously 6px */
background:#eee;
transition: all 0.8s ease-in-out, color 0.1s, background 0.1s;
}
Update:
Since the padding and border are needed, you can adjust your ruleset to have these values while the menu circles have the open class and remove them when the class is not present
http://jsfiddle.net/avt0fvk4/
I have a site that wanted a TV credits-style ticker & I just went back to revisit & check up on them & noticed that the display was starting to break down. I'm hoping that those of you more experienced JS veterans can help me figure out where I've gone wrong, here.
My JS is as follows:
$('.sidescroll').totemticker({
row_height : '120px',
next : '#ticker-next',
previous : '#ticker-previous',
stop : '#stop',
start : '#start',
mousestop : true
});
jQuery(".sidescroll li").append("<hr />");
and the my CSS for it is as follows:
.sidescroll {
height: 100% !important;
display: block;
}
.sidescroll li {
margin: 10px;
text-align: left;
height: 120px;
}
.sidescroll hr {
height: 3px;
border: 0;
box-shadow: inset 0 3px 3px -3px rgba(92, 71, 112, 0.75);
}
.sidescroll li a {
font-family: 'lulo' !important;
}
.sidescroll li a:hover {
text-decoration: none;
color: #5c4770;
}
The ticker is for their blog posts, sort of a running list of posts, which is being pulled by the list category plugin & is limited to 20 characters for the excerpt. The issue that I noticed was that the horizontal row is starting to interact with a couple of the posts, which was not the case when the site was set up.
Turns out it's fairly simple. There is sometimes too much content in the boxes and they overflow into the one below. Either too much text or the word wrapping is splitting over too many lines.
Bonus (completely optional)
We can elegantly suppress this behavior (assuming the use of CSS3 to generate a gradient).
First we modify the javascript to insert the horizontal line as first child, then we insert a div with a class as a last child:
jQuery(".sidescroll li").prepend('<hr />');
jQuery(".sidescroll li").append('<div class="fadeToWhite"></div>');
Then we modify the css:
.sidescroll {
height: 100% !important;
display: block;
}
.sidescroll li {
margin: 10px;
text-align: left;
height: 120px;
/* additions: */
position: relative;
overflow: hidden;
}
.sidescroll hr {
height: 3px;
border: 0;
box-shadow: inset 0 3px 3px -3px rgba(92, 71, 112, 0.75);
}
.sidescroll li a {
font-family: 'lulo' !important;
}
.sidescroll li a:hover {
text-decoration: none;
color: #5c4770;
}
/* additions */
.sidescroll li div.fadeToWhite {
width: 100%;
height: 20px;
position: absolute;
bottom: 0;
background: linear-gradient(transparent, white);
}
This will hide any overflowing text while turning the additional div into a fade-to-white bar at the bottom of each list element to avoid a hard text-cut.