Using Javascipt to fade between browser background colours - javascript

First post, starting to explore JS.
I am using elearning software called Articualte Storyline. I export everything in my courses in html. It is basically a supercharged Powerpoint but one of the options is to create a trigger to run JS which opens up lots of additional options.
I have been using the JS below to set the browser background colour to something of my choosing.
I have then repeated the code on the next slide, so when the user moves through the exported course it changes the background colour.
However, this change of colour is very abrupt so I would prefer it to slowly fade between colour 1 and colour 2.
I imagine that on the second slide, I instruct the colour to be colour 1, then after a delay transition to the new colour 2, but I have become stuck!
Any help gratefully received, thanks!
document.body.style.background="linear-gradient(120deg, #f093fb 0%, #f5576c 100%)";

You can try this:
document.body.style.transition = "background 0.5s ease;"

Use a transition in the CSS
function rand() {
return Math.floor(Math.random() * 256);
}
function randomBG() {
var bgColor = "rgb(" + rand() + "," + rand() + "," + rand() + ")";
document.body.style.background = bgColor;
}
window.setInterval(randomBG, 2000);
body {
background-color: #AAEE33;
transition: background 500ms linear;
}

Related

How to change value of CSS variable as page scrolls gsap?

I have a css variable named --color. I want to change the value of this css variable as the page scrolls down. The scrolling of the page should "scrub" the value.
Example: --color starts out at rgb(255, 255, 255). As the page scrolls down, the value gets closer to and eventually reaches rgb(0, 0, 0) upon scrolling down all the way. When scrolling back up, the value should slowly advance back to rgb(255, 255, 255), reaching it by the time the page is scrolled up completely.
I have been trying to achieve this with GSAP but have yet to find any success, although I believe it must be possible with the library.
Sure, here you go:
gsap.to("body", {
"--color": "black",
scrollTrigger: {
start: 0,
end: "max",
scrub: true
}
});
https://codepen.io/GreenSock/pen/WNOzWaM?editors=0110
By the way, there are dedicated GSAP forums at https://greensock.com/forums
unfortunately I am not familiar with GSAP, but
here is the link that describes how to get the computed styles and the property value of that style with JS.
You need to listen to scroll event and change the value of the css variable inside of the listener, like so:
document.addEventListener('scroll', function(e) {
var root = document.querySelector(':root');
var newColor = // do your color calculations here;
root.style.setProperty('--color', newColor);
}
here are some useful links.
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration/setProperty
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration/getPropertyValue
https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
Here is an average calculation for your rgb() color that might be fine enough to go from light to dark and back. It is far to be perfect.
const body = document.querySelector("body ");
const bodyHeight = document.querySelector("body").offsetHeight;
body.innerHTML = '<p style="position:sticky;top:0;">Body Height: ' + bodyHeight + 'px <br>Window Height: ' + window.innerHeight + 'px</p>';
const root = document.querySelector(":root");
window.addEventListener("scroll", (event) => {
let scroll = this.scrollY;
let ratio = (scroll / (bodyHeight - window.innerHeight ) ) ;
let rgbvalue = 255 - ratio * 255;
root.style.setProperty( "--color", "rgba(" + rgbvalue + "," + rgbvalue + "," + rgbvalue + ")"
);
console.log(rgbvalue);
});
body {
background: var(--color, rgb(255, 255, 255));/* use defaul trgb(255, 255, 255) untill var is set from js */
height: 300vh;
}
<div></div>
It's helpful when you provide a code snippet to show what has already been attempted. Helps with specificity of the answer.
To give a general answer to your question, you can use ScrollTrigger to define the point at which the color changes. Define the markers where it should start changing and use properties such as coloronEnter, onLeave, onEnterBack to your callback to change the color.

Mix an HSLA color with white and convert to non-alpha HSL with Chroma.js

I have a design system with many, many colors. I have created a table of colors where all colors are mixed with every other color and color contrast ratio (CCR) of each combination is output. The goal is to flag inaccessible color combinations.
I am using Chroma.js to manipulate the colors and output the CCRs. It works brilliantly with the bulk of my HSL-defined colors.
The trouble comes when my design system uses a color with an alpha channel. Determining how a pair of colors performs with CCR when one or both of them are transparent is problematic. I am trying a few different things to mix or blend a HSLA color with white and then run the contrast function on that. Here is a snippet of what I am doing:
// where either foreground or background has an alpha value present less than 1
var background = chroma.mix(background, '#fff', 1, 'lab').css();
var foreground = chroma.mix(foreground, background, 1, 'lab').css();
var ccr = chroma.contrast(foreground, background);
// lab gets the closest but not the same as the way CSS overlays colors
The results are visualized with this graphic I put together. Left are two colors with an overlay of them in the middle. In Adobe Illustrator, I used 25% transparency on the tan color and a "normal" blend mode. I did the same in CSS and then screen-shotted it, then measured the resulting color mix in Photoshop. To the right are the outputs of Chroma color functions:
Having tried what I understand to be the options in Chroma.js, I am wondering what else I can try to get my results closer to the browser output so that my CCR tests will be accurate. Thanks all.
Thanks to the accepted answer from #GrahamRitchie, my output table now looks like this. The little "composite" labels show the colors that were produced by these functions, while the main output still layers the transparent colors over each other and the background.
I do not know how to do this with the library you mentioned (Chroma.js) but hopefully a vanilla JavaScript function will help.
Please note that the below function always assumes an opaque background colour to work correctly (hence background RGB and foreground RGBA).
If you need to work with 2 colours that both have alpha channels you would run the function on the background colour first (as the foreground colour) with a white background and then combine the two colours.
The function will also combine two RGB colours, simply omit the alpha channel when passing your RGB colour (convertToRGB({r,g,b}, {r,g,b}))
function convertToRGB(frontRGBA, backgroundRGB){
var rtrn = {};
//allows the function to just accept a front colour and assume the background is a plain white.
backgroundRGB = backgroundRGB || {r:255,g:255,b:255};
//allows a RGB value to be passed in assuming full alpha channel.
frontRGBA.a = frontRGBA.a || 1;
//normalise the alpha channel across the foreground and background.
rtrn.r = ((1 - frontRGBA.a) * backgroundRGB.r) + (frontRGBA.a * frontRGBA.r);
rtrn.g = ((1 - frontRGBA.a) * backgroundRGB.g) + (frontRGBA.a * frontRGBA.g);
rtrn.b = ((1 - frontRGBA.a) * backgroundRGB.b) + (frontRGBA.a * frontRGBA.b);
//just check that we don't end up with a value greater than 255 for any channel.
rtrn.r = (rtrn.r > 255) ? 255 : rtrn.r;
rtrn.g = (rtrn.g > 255) ? 255 : rtrn.g;
rtrn.b = (rtrn.b > 255) ? 255 : rtrn.b;
return rtrn;
}
var backgroundRGB = {r:165,g:193,b:211};
var frontRGBA = {r:210,g:203,b:178,a:0.25};
//used for example
var rgb = convertToRGB(frontRGBA, backgroundRGB);
document.querySelector(".output").style.background = "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
document.querySelector(".output").innerHTML = "Output<br/>R:" + rgb.r + "<br/>G:" + rgb.g + "<br/>B:" + rgb.b;
.container div{
width: 200px;
height: 200px;
float: left;
}
.div1{
background: rgba(165,193,211,1);
}
.div2{
background: rgba(210,203,178,0.25);
}
<div class="container">
<div class="div1">Background<br/>R:165<br/>G:193<br/>B:211<br/>A:1</div>
<div class="output">Output</div>
<div class="div2">Foreground<br/>R:210<br/>G:203<br/>B:178<br/>A:0.25</div>
</div>

PHP: Add div background color using decimal value (1= black and 0 = white)

So in my gaming system after I query the players database, I get a value between from 0 to 1. 0 should represent white and 1 should represent black. 0.01 to 0.99 represents the shades from white to black.
I use the gaming data to show the players profile details on a webpage.
How can I dynamically create a logic to generate the color code based on this decimal value? I need to make the background color of the div of each player a shade of grey as represented by the player's orientation number (0 to 1)
I tried to add background-color:black to the div and then reduce opacity to simulate change in shade. Unfortunately this also makes the content inside the div transparent too. I tried adding opacity:1 to inside div but it did not work.
So I think finding a way to convert the decimal value to a hex value between black and white must be the way.
Any insight is greatly appreciated!
The colors are expressed in RGB (Red, Green, Blue) with each value ranging between 0 and 255, so simply multiply your value by 255 for each color component and then set your div's background color like this:
<div id="myDiv">This is a color test</div>
<script>
var value = 0.1;
var color_component = Math.ceil(255 * (1 - value));
var color = "rgb(" + color_component + "," + color_component + "," + color_component + ")";
document.getElementById("myDiv").style.backgroundColor = color;
</script>
Racil had the right idea, but constructed the color improperly. One way you could do it would be to calculate the color component like he suggested:
var color_component = 255 * (1 - value);
The you could use this to generate the color into something like this:
var color = 'rgb(' + value + ', ' + value + ', ' + value + ')';
Or if you wanted to be extra sneaky, you could convert this into a hexadecimal color by converting the color component to hexadecimal, like this:
var hex = new Number(color).toString(16);
var color = '#' + hex + hex + hex + ';';
if you want use only PHP (better if the result beetween 0 and 1 come from PHP or database) I think this can be good way:
<?php
$res = 0.4; //that you have to put you result between 0 and 1
$rgb= intval($res*255);
$color = "rgb(".$rgb.", ".$rgb.", ".$rgb.")"; // the result of the code... for example "rgb(2, 2, 2)"
?>
then you have only to echo the color on your div style.

Using Javascript & CSS Animations to create a TEXT marquee

I am preying somebody can help me out..
Brief History:
Im building a radio station on the internet, the Webpage will display metadata for songs playing and songs played in the past...
So far i have managed to build a MYSQL database, Query the database in PHP, encode the array of data in JSON, use ajax to set a timer to query the database and JavaScript to parse the data to HTML...
I have also managed to get my head around HTML & CSS to an extent..
I am brand new to coding and everything is coming along nicely and am doing some courses in JavaScript but what i want is far too advanced for any course i have taken so far....
The Question:
I wish to make a TEXT marquee that will display the name of the song currently playing.
The text marquee will have some rules.
Rule 1: The name of the song will stay static on screen if it is equal to or less than the display area.
Rule 2: If the name of the song is greater than the display area then it needs to animate.
Before you go any further i need to note that i have looked at a few JQuery marquees but none of them suite my needs
The Maths:
FIXED DIV WIDTH = 257.4 Pixels
(This is the "wrapper" which will contain the variable text (which is a little bigger than my MAXIMUM TEXT WIDTH so it looks pretty...)
VARIABLE TEXT WIDTH = x characters
(defined by "list0title" which is variable data from MYSQL dB) (the characters will need to be converted to pixels for use with MAXIMUM TEXT WIDTH)
MAXIMUM TEXT WIDTH = 250 Pixels
(this is the maximum text that fits in the "wrapper" comfortably, if VARIABLE TEXT WIDTH is equal to or less than MAXIMUM TEXT WIDTH the text will be static, otherwise the text will animate in a ping pong style)
ANIMATION:
VARIABLE TEXT WIDTH - MAXIMUM TEXT WIDTH = PIXELS TO ANIMATE
(for example if my VARIABLE TEXT WIDTH was 150 pixels and my MAXIMUM TEXT WIDTH was 100 PIXELS i would need to animate the text by 50 pixels 150-100 = 50 pixels)
So this above is me explaining The JavaScript / CSS intergrated script i need in the best way i can..
I will include my JavaScript Below so you can see how the information is obtained from the MYSQL database and also provide the example code for the animation.
JAVASCRIPT:
function getPlaylist()
{
var xmlhttp,
timer;
if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}
else
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function ()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
var list = eval ('('+xmlhttp.responseText+')');
{
document.getElementById("list0artist").innerHTML=list[0].artist;
document.getElementById("list0title").innerHTML=list[0].title;
document.getElementById("list0titlelength").innerHTML=list[0].title.clientwidth;
document.getElementById("list0label").innerHTML=list[0].label;
document.getElementById("list0albumyear").innerHTML=list[0].albumyear;
document.getElementById("list0picture").innerHTML='<img src="/testsite/covers/' + list[0].picture + '" width="169" height="169"/>';
document.getElementById("list1artist").innerHTML=list[1].artist;
document.getElementById("list1title").innerHTML=list[1].title;
document.getElementById("list1label").innerHTML=list[1].label;
document.getElementById("list1albumyear").innerHTML=list[1].albumyear;
document.getElementById("list1picture").innerHTML='<img src="/testsite/covers/' + list[1].picture + '" width="83px" height="83px"/>';
document.getElementById("list2artist").innerHTML=list[2].artist;
document.getElementById("list2title").innerHTML=list[2].title;
document.getElementById("list2label").innerHTML=list[2].label;
document.getElementById("list2albumyear").innerHTML=list[2].albumyear;
document.getElementById("list2picture").innerHTML='<img src="/testsite/covers/' + list[2].picture + '" width="83px" height="83px"/>';
document.getElementById("list3artist").innerHTML=list[3].artist;
document.getElementById("list3title").innerHTML=list[3].title;
document.getElementById("list3label").innerHTML=list[3].label;
document.getElementById("list3albumyear").innerHTML=list[3].albumyear;
document.getElementById("list3picture").innerHTML='<img src="/testsite/covers/' + list[3].picture + '" width="83px" height="83px"/>';
document.getElementById("list4artist").innerHTML=list[4].artist;
document.getElementById("list4title").innerHTML=list[4].title;
document.getElementById("list4label").innerHTML=list[4].label;
document.getElementById("list4albumyear").innerHTML=list[4].albumyear;
document.getElementById("list4picture").innerHTML='<img src="/testsite/covers/' + list[4].picture + '" width="83px" height="83px"/>';
}
}
};
xmlhttp.onerror = function()
{
clearTimeout(timer);
};
xmlhttp.open("GET", "playlist.php?t=" + Math.random(), true);
xmlhttp.send();
timer = setTimeout(getPlaylist, 1000);
}
CSS ANIMATION:
<!DOCTYPE html>
<html>
<head>
<script src="/testsite/OneSecondPlaylist.js"></script>
<style type="text/css">
#wrapper {
width: 257.4px;
height: 41.85px;
overflow: hidden;
background-color: #383838;
color: #FFFFFF;
line-height: 41.85px;
font-size: 80%;
font-family: baumans;
color: #FFFFFF;
}
.textbox {
-moz-animation-duration: 4s;
-moz-animation-name: slidein;
-moz-animation-iteration-count: infinite;
-moz-animation-direction: alternate;
-moz-animation-timing-function: linear;
white-space:nowrap;
}
#-moz-keyframes slidein {
from {
margin-left:3%;
}
to {
margin-left:-33%;
}
</style>
</head>
<body onload="getPlaylist()">
<script>var __adobewebfontsappname__="dreamweaver"</script><script src="http://use.edgefonts.net/baumans:n4:default.js" type="text/javascript"></script>
<div id="wrapper">
<div id="list0artist"></div>
</div>
<div id="wrapper">
<div id="list0title" class="textbox"></div>
</div>
</body>
</html>
ANIMATION NOTE: I am aware that i need to play with the webkits to get it working on all browsers
I hope i have not included too much code, i felt it was important to show it in its entirety as you may have some pointers outside of the question i am asking..
So to sum up i am basically asking you guys to help me code a JavaScript / CSS intergrated script that will animate based upon the rules i have defined.
Thanks for reading this through, i hope you dont think im being lazy asking for this, i feel i am making good headway for somebody who has zero coding knowledge and just need a push in the right direction!!!.. Many Thanks!!! Justin..
var texts = document.getElementsByClassName('text'); // Class I added to innards
for (var i = 0; i < texts.length; i++) {
if (texts[i].parentNode.offsetWidth < texts[i].offsetWidth) {
texts[i].classList.add("textbox");
}
}
Demo
Some notes:
You can't have decimal pixels like .4px, it will be rounded up or down based on the browser
I'd recommend pausing at some point in the animation, continuous movement is annoying for users
Using margins is kind of iffy, I might opt for using left instead. This is what I did in the demo
Edit
To fix the positioning issue for the animation you can use transforms instead of position:absolute.
transform:translateX(calc(-100% + 257px)); /* -100% + parent width */
Demo
But like I said before, using a js solution would likely be better

Raphael setting transparent png opacity loses alpha channel

I'm using Raphael 2.1.0.
When I animate the opacity of a transparent PNG under IE8, the transparency animates well. ie: 'from' an opacity of 0.0 'to' an opacity of 1.0.
After the opacity animation has ended, I want to set/restore the image's position/opacity to a pre-animation state, but the alpha channel of the image becomes opaque. Where there was once a transparent background there is now a white square.
With an SVG renderer - Chrome and Firefox - things are fine. I've tried chaining the image, translation and alpha to no avail.
Here's the code:
var element = this._paper.image(image.Url(), 0, 0, width, height);
var removeOnStop = true;
var fromParams = {}
var toParams = {};
// From options
fromParams.opacity = options.from.alpha;
// ...
element.attr(fromParams);
// To options
toParams.transform = 'T300,300';
toParams.opacity = options.to.alpha;
// Animate
var anim = Raphael.animation(toParams, duration, 'linear', function() {
if (removeOnStop) {
element.attr({ opacity: defaultProperties.alpha });
element.transform('T' + defaultProperties.left + ',' + defaultProperties.top);
}
}).repeat(repeat);
element.animate(anim);
Any help would be greatly appreciated.
I tried the following
Animating the alpha, everywhere, but this causes null reference issues within Raphael
Chaining translate()/transform() and attr()
Applying filters directly to the object
Changing the order (attr before transform and vice versa)
In the end, the working solution is to translate AND set the opacity using attr:
if (removeOnStop) {
element.attr({ opacity: defaultProperties.alpha });
element.transform('T' + defaultProperties.left + ',' + defaultProperties.top);
}
became
if (removeOnStop) {
element.attr({ transform: 'T' + defaultProperties.left + ',' + defaultProperties.top,
opacity: defaultProperties.alpha });
}
Importantly, you must do this when initially creating the image and setting the initial opacity.
I hope this will save people future trouble.

Categories