100% high vertical marquee with CSS at fixed scroll speed - css

I need to replace a vertical scroller with a CSS equivalent, for compliance reasons. The replacement needs to be a 100% high marquee, scrolling vertically at a fixed speed.
This example does what I need it to with three exceptions: https://codepen.io/strongpom/pen/qmooZe
I've tried using the code linked above, but find a way to accommodate the following three requirements:
(1) I need it to be 100% high, and for the text to scroll from the top to the bottom.
(2) I can't specify the length of the slider div, because it will be determine by (variable) contents. This means I cant set absolute scroll positions, other than that the top of the div should start at the bottom of the viewport, and keep scrolling until the bottom of that div hits the top of the viewport.
and
(3) The scrollspeed cannot be fixed at e.g. 15 seconds, because if there's lots of content, it then scrolls too fast, whilst if there's little content, it scrolls too slowly. I need to be able to specify a fixed scrolling speed, independent of length.
.container {
width: 20em;
height: 10em;
margin: 2em auto;
overflow: hidden;
background: #ffffff;
position: relative;
}
.slider {
top: 1em;
position: relative;
box-sizing: border-box;
animation: slider 15s linear infinite;
list-style-type: none;
text-align: center;
}
.slider:hover {
animation-play-state: paused;
}
#keyframes slider {
0% { top: 10em }
100% { top: -14em }
}
.blur .slider {
margin: 0;
padding: 0 1em;
line-height: 1.5em;
}
.blur:before, .blur::before,
.blur:after, .blur::after {
left: 0;
z-index: 1;
content: '';
position: absolute;
width: 100%;
height: 2em;
background-image: linear-gradient(180deg, #FFF, rgba(255,255,255,0));
}
.blur:after, .blur::after {
bottom: 0;
transform: rotate(180deg);
}
.blur:before, .blur::before {
top: 0;
}
p {
font-family: helvetica, arial, sans serif;
}
<div class="container blur">
<ul class="slider">
<li><p> Hello, it's me</p></li>
<li><p> I was wondering if after all these years you'd like to meet</p></li>
<li><p>To go over everything</p></li>
<li><p> They say that time's supposed to heal ya</p></li>
<li><p> But I ain't done much healing</p></li>
</ul>
</div>

I could not find a pure CSS way to have a consistent speed, but with a little math and small javascript, you can achieve fixed speed with variable height items. The key factor below is the / 500 which is in pixels per second. The code below will scroll at approx 500 px per second, no matter the length of the items.
Height can accommodate your design.
This will loop smoothly according to your request.
The scroll speed is what you determine regardless of length.
The javascript/css is verbose for readability.
CodePen - If still available, otherwise code below.
HTML
<ul class=slider>
<li>Item</li>
...
</ul>
CSS
* { padding: 0; margin: 0; box-sizing: border-box; }
body { overflow: hidden; height: 100%; }
.slider {
position: absolute;
list-style-type: none;
text-align: center;
animation: slider linear infinite;
}
.slider li { line-height: 50px; width: 100vw; }
#keyframes slider {
0% { transform: translateY(100vh) }
100% { transform: translateY(-100%) }
}
JS
window.onload = function() {
var lineHeight = document.querySelector(".slider li").clientHeight;
var viewHeight = window.innerHeight;
var slider = document.querySelector(".slider");
var time = (slider.offsetHeight * 2.0 + viewHeight * 2) / 500.0;
slider.style.animationDuration = time + "s";
}

Related

I can't get text to interact with an image properly and it is causing me to create many breakpoints in order for it to display properly

I have an image of a soundman holding a boom that slides in from the left on my index page. In order to have the text underneath the boom, I have the text and the image on different axes. There is something problematic when it comes to different screen sizes because the text moves up and down quite a bit depending on the screen size which can create an overlap with the image of the boom. I was in the process of creating multiple breakpoints (oh my god there are so many) when I thought maybe there would be a better way to have the text and the image all adjust in relation to each other.
codepen: https://codepen.io/arpunk/pen/vYLbvOG
site: www.productionsound.net
Is there a better way to code the image/text?
Pasted the appropriate code below but the full code/html is on codepen
Thank you!
.mainwrapper {
position: absolute;
overflow: hidden;
z-index: -1;
width: 100%;
height: 100%;
}
.mainlogo {
position: absolute;
left: -100%;
max-width: 90%;
height: auto;
-webkit-animation: slide 0.5s forwards;
-webkit-animation-delay: 2s;
animation: slide 0.5s forwards;
animation-delay: .5s;
padding-left: 20px;
}
.mainlogoname {
font-family: 'Montserrat', sans-serif;
font-size: 140%;
width: 58%;
height: auto;
line-height: 25px;
position: absolute;
top: 350px;
left: 37%;
z-index: -1;
padding-bottom: 60px;
}
If you use the vw unit, you can set the top position based on the width of the browser viewport. Then you can have the text move up and down as the image shrinks and grows, and you only need one media query to make it stay put when the image reaches its full size.
Updated Codepen
.mainlogoname {
top: calc(100px + 20vw);
left: 38%;
}
#media (min-width: 1100px) {
.mainlogoname {
top: 330px;
}
}
See CSS-Tricks: Fun with Viewport Units for more info on the vw unit.

Bug in html <marquee> style CSS animation

Here is a short codepen of a simple css animation that I'm struggling to work with. Code also below:
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
}
#keyframes navscroll {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
Its supposed to be a scrolling navbar of divs, but I'm having two issues:
The inner divs are stacking vertically, not horizontally...
The inner divs are scrolling across only a small percentage of the nav bar / outer div...
Ideally, if there were many divs in the navscroll div, only 5-6 of them would display anytime on the screen, although the navbar would always be scrolling and those other divs would make their way onto the screen eventually. (similar to stock tickers ticking across the top of the TV screen). Any help with this is appreciated, thanks!!
div is a block level element (means it has display: block; by default). These create a line break before and after themselves. Use display: inline-block; and make sure they align properly using vertical-align: middle;.
2nd problem: translateX(100%) here the percentage does not refer to the parent element, but to the div being animated.
.navscroll {
width: 100%;
height: 100px;
padding: 5px;
overflow: hidden;
position: relative;
background-color: red;
white-space: nowrap;
}
.navscroll div {
position: relative;
width: 200px;
height: 100%;
line-height: 50px;
text-align: center;
background-color: blue;
opacity: 1;
border-radius: 5px;
transform: translateX(100%);
animation: navscroll 15s linear infinite;
/* this does the magic: */
display: inline-block;
vertical-align: middle;
}
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -100%;
}
}
<div class="navscroll">
<div>Why arent these</div>
<div>Side by side</div>
<div>or sliding across the WHOLE navbar</div>
</div>
As per your question about how to create a snippet here:
The inner divs are stacking vertically because the default styling for a div is display: block. Adding the styles display: inline-block; vertical-align: top; to your .navscroll div rules will set them side by side, aligned to their top edges.
The animation is starting in the middle, and not all the way to the right like you intend because of how transform: translate() works. transform refers to the object being transformed, not its parent. So, translating something 100% of it refers to the width of the object. Try animating the position, something like this instead:
#keyframes navscroll {
0% {
left: 100%;
}
100% {
left: -600px;
}
}
EDIT: Also, remove the initial transform: translateX(100%); and you can simply animate the left position to -600px (3x the width of the each block).

How can I animate this sequence in CSS/LESS?

This is my first foray into animation. I'm trying to create an animated splash screen featuring a sliding logo and two snippets of text that fade in and out. The layout when the text is shown should look like this:
*------------------------*
| |
| |
| [L] Lorem ipsum etc. |
| |
| |
*------------------------*
The animation should progress like so:
Logo [L] begins in the center
Logo slides left making room for each piece of text
Text 1 fades in and out of view to the right of logo
Text 2 fades in and out of view in the same location
Logo slides back to center
The problem I'm facing is coming up with the right combination of element hierarchy and animatable properties to put everything where it should be.
My best attempt (below) starts with the text at 0 max width and 0 opacity. I animate max-width on the second, wider text to push the logo aside, then wait an appropriate interval while a second animation reveals the first text using opacity. But I still cannot make both texts appear properly in the same place while the logo stays put. (Assuming there is room on the screen, both texts should appear vertically and horizontally centered in the space to the right of the logo, but the first text will be one line and second will be two lines.)
I'm not sure if this is even the right approach. To make the design responsive I want to avoid specifying absolute dimensions except for the size of the logo and font. I am using Bootstrap if that provides any help.
Codepen example
HTML:
<div class="overlay">
<div class="overlay--splash"></div>
<div>
<div id="overlay__one" class="h1 overlay--text">Short piece of text</div>
<div id="overlay__two" class="h1 overlay--text">Slightly longer text <br /> which will span two lines.</div>
</div>
</div>
LESS:
.overlay {
z-index: 999;
position: absolute;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,0.9);
padding: 100px;
.overlay--splash {
width: 200px;
min-width: 200px;
height: 200px;
margin: 1em;
display: inline-block;
align-self: center;
justify-content: center;
background-image: url("/images/app-icon.png");
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: 200px; }
.overlay--text {
display: inline-block;
width: auto;
max-width: 0;
font-size: 64px;
font-weight: 900;
font-family: sans-serif;
color: #dark-blue;
opacity: 0;
}
#overlay__one {
.keyframes(fade-in-out; {
0% { opacity: 0; }
40% { opacity: 0; }
60% { opacity: 1; }
80% { opacity: 1; }
100% { opacity: 0; }
});
.animation(fade-in-out 5s linear)
}
#overlay__two {
.keyframes(slide-fade; {
0% { opacity: 0; max-width: 0; }
10% { opacity: 0; max-width: 0; }
20% { opacity: 0; max-width: 1600px; }
50% { opacity: 0; max-width: 1600px; }
60% { opacity: 1; }
70% { opacity: 1; }
80% { opacity: 0; max-width: 1600px; }
90% { max-width: 0; }
});
.animation(slide-fade 10s linear)
}
}
Rather than trying to do all of the animation directly in CSS it turned out to be much easier to stack everything in the center of the screen using transform and then animate the transitions with jQuery: https://codepen.io/anon/pen/BWpQXg
var dX = $("#overlay__two").width() / 2;
$(".overlay--splash").animate({left: "-=" + (dX + 140)});
$("#overlay__one").delay(1000).fadeToggle(1000).fadeToggle(1000);
$("#overlay__two").delay(3000).fadeToggle(1000).delay(1000).fadeToggle(1000);
$(".overlay--splash").delay(6000).animate({left: "+=" + (dX + 140)});

Scaling a 1% width div up 100 times doesn't cover the full width of the parent

I'm trying to make a progress bar.
You'd think that a div with a width of 1% scaled up horizontally 100 times would span the width of its parent, but it doesn't. The amount of space left seams to depend on my window size, so I think this might be a rounding issue in the browser. Is there anything I can do to make this work?
I'm changing the progress of this bar quite often, so I don't want to change the bar's width property every time, as that would cause performance issues.
body {
margin: 0;
padding: 0;
}
#container {
background-color: red;
position: fixed;
left: 0;
right: 0;
top: 0;
padding: 0;
margin: 0;
height: 100px;
}
#progress {
position: absolute;
left: 0;
top: : 0;
width: 1%;
height: 100%;
background-color: yellow;
transform: scale(100, 1);
transform-origin: left top;
}
<div id="container">
<div id="progress">
</div>
</div>
I also made a codepen to demonstrate this issue: http://codepen.io/bigblind/pen/Zbozjv
The amount of space left seams to depend on my window size, so I think
this might be a rounding issue in the browser.
Yes. It is.
I don't want to change the bar's width property every time
I am not trying to debate the performance thingy here, but just trying to concentrate on the problem that if not width then what property could be used?
Well, you could just turn your progress on its head. Instead of the #progress div expanding to show the amount of progress, slide it out of the way to reveal the background #container div to show the amount of progress. Use the translate to slide the progress away.
In the demo below, hover to see the transform in effect.
Demo Fiddle: http://jsfiddle.net/abhitalks/y2o7yub9/1
Demo Snippet:
* { box-sizing: border-box; padding: 0; margin: 0; }
html, body { width: 100%; }
#container{
background-color: yellow; position: fixed;
left: 0; right: 0; top: 0;
height: 100px; width: 100%;
overflow: hidden; white-space: nowrap;
}
#progress{
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background-color: red;
transform: translateX(0%); transition: transform 0.5s;
}
#container:hover > div { transform: translateX(100%); }
<div id="container">
<div id="progress"></div>
</div>
Problem
Looks to me that there is a rounding issue.
On a 1920 pixel monitor, 1% gets translated to 19.188 pixels which gets rounded down to 19 pixels
19 pixels * 100 = 1900 pixels which leaves a 20 pixel gap.
More information here: http://ejohn.org/blog/sub-pixel-problems-in-css/
Edit: if you rescale your browser, on some widths, the red part is larger, smaller or gone; which confirms the rounding issue.
Solution
Declare a progress bar with a fixed width : 200px
Initialise it to 2px which can't be rounded up/down

Animated transition not starting at the right position

I'm working on a site with a knotted rope-style bar that expands to show more information on hover, and I'm having issues getting the animation to look right. (Here's a staging link: http://couchcreative.co/tcc/).
Currently, the bar for the first step will move down to the bottom of the box before it animates upwards to its new position, while I want it to just move up to its new position on hover without starting at the bottom of the hover box. Can anyone help explain why this is happening? The relevant CSS starts with the ".look" class.
Apologies if I'm not explaining this right, but hopefully when you visit the site you'll see what I mean about the animation looking a bit… off. Thanks for the help!
I would rework your HTML structure to make it more semantic and less repetitious.
Demo: http://jsfiddle.net/krmn4/5/
HTML:
<a href="/testicularcancer/" class="look">
<figure><img src="http://couchcreative.co/tcc/img/look.png" /></figure>
<div class="bar"></div>
<div class="off">
<h4>Look</h4>
</div>
<div class="on">
<h4>Relax your scrotum.</h4>
<p>Check your testicles just after you’ve had a bath or shower, when the muscles in the scrotum are relaxed, making it easier for you to feel any lumps, growths or tenderness. Stand in front of the mirror. Look for any swelling on the skin of your scrotum.</p>
<span>Learn More</span>
</div>
</a>
CSS:
.look {
position: absolute;
bottom: 0;
left: 0;
width: 235px;
overflow: hidden;
/* optional styling */
color: #000;
text-align: center;
text-decoration: none;
}
.look h4 {
/* optional styling */
line-height: 48px;
font-size: 20px;
font-weight: bold;
}
.look .bar {
height: 48px;
background: url(http://couchcreative.co/tcc/img/step_1.png) 0 0 repeat-x;
margin: -24px 0 0; /* half of height */
/* necessary so figure img doesn't overlap */
position: relative;
z-index: 1;
}
.look figure,
.look .off,
.look .on {
-webkit-transition: all 300ms linear;
-moz-transition: all 300ms linear;
transition: all 300ms linear;
height: 0;
opacity: 0;
overflow: hidden;
}
.look figure {
/* optional styling */
background-color: #b2d5e6;
padding: 12px;
margin: 0;
}
.look .off {
height: 48px;
opacity: 1;
}
/* hover state */
.look:hover .off {
height: 0;
opacity: 0;
}
.look:hover figure {
height: 120px; /* or however tall it needs to be */
opacity: 1;
}
.look:hover .on {
height: 220px; /* or however tall it needs to be */
opacity: 1;
}

Resources