CSS Toggle not displaying changes - javascript

I wrote a simple code to change font and color of text on google and it worked but when I tried to implement it into a toggle on / off switch, the changes don't appear.
I used ChatGPT to get some assistance in error reduction and general knowledge of what I did wrong (aware that it does give incorrect information) but after running quite a number of iterations through the prompts, it no longer has any substantial changes that it can detect.
//Get the URL
const site = window.location.hostname
//Function to add custom CSS
let customStyle;
const Add_Custom_Style = css => customStyle = document.head.appendChild(document.createElement("style")).innerHTML = css;
const Remove_Custom_Style = () => customStyle.remove();
//Function to change CSS
function changeCSS(){
//Function for Google.com
if (site.includes("google.com")){
Add_Custom_Style(`
#import url('https://fonts.googleapis.com/css2?family=Advent+Pro:wght#300&display=swap');
* {
font-family: 'Advent Pro', sans-serif !important;
color: #fff !important;
}
a {
color: #b0dff4 !important;
font-size: 140%;
}
h1, h2, h3, h4, h5, h6 {
color: #b0dff4 !important;
}
`)
}
}
//Function to remove CSS
function removeCSS(){
customStyle.remove();
}
//Toggle function on off
window.onload = function() {
const cssToggleBtn = document.getElementById("togBtn");
cssToggleBtn.addEventListener("change", function(){
if(cssToggleBtn.checked){
changeCSS();
}
else{
removeCSS();
}
});
};
This is the code I am currently using. If I missed something or there is a blatant error, please point it out. Thank you!

//Get the URL
const site = window.location.hostname
//Function to add custom CSS
let customStyle;
const Add_Custom_Style = (css) => {
customStyle = document.createElement("style")
document.head.appendChild(customStyle).innerHTML = css;
}
const Remove_Custom_Style = () => customStyle.remove();
//Function to change CSS
function changeCSS(){
//Function for Google.com
//if (site.includes("google.com")){// Are you sure? Running this under google.com domain?
Add_Custom_Style(`
#import url('https://fonts.googleapis.com/css2?family=Advent+Pro:wght#300&display=swap');
* {
font-family: 'Advent Pro', sans-serif !important;
color: #fff !important;
}
a {
color: #b0dff4 !important;
font-size: 140%;
}
h1, h2, h3, h4, h5, h6 {
color: #b0dff4 !important;
}
`)
//}
}
//Function to remove CSS
function removeCSS(){
customStyle.remove();
}
//Toggle function on off
window.onload = function() {
const cssToggleBtn = document.getElementById("togBtn");
cssToggleBtn.addEventListener("change", function(){
if(cssToggleBtn.checked){
changeCSS();
}
else{
removeCSS();
}
});
};
<h1>Demo</h1>
<p>
Google
</p>
<label>
<input id="togBtn" type="checkbox">
Toggle.
</label>
if (site.includes("google.com")){ means site constant that get current URL must be google.com.
Are you sure that you running this under Google domain?
You have customStyle variable and call to this with .remove() to remove <style> element but you assign it incorrectly.
You already delcared Remove_Custom_Style as a function to remove <style> element on customStyle variable. So, you don't have to declare removeCSS() function to do the same thing again.
Choose one!

Related

i am supposed to change the text color, size, and font when you hover the mouse over the text. How can i made this happen continiuously?

the mouseon Function changes the text to green, and its position. i also need it to change font and size. i need these two functions to happen all the time when the mouse is hovered over the text. i want the mouse off function to bring the text back to normal.
function mouseOn(){
document.getElementById("text").style.color = "green";
document.getElementById("text").style.position = "fixed";
document.getElementById("text").style.left = "300px";
}
function mouseOff(){
document.getElementById("text").style.position = "auto";
document.getElementById("text").style.color = "blue";
}
<h1 id="text" onmouseover= "mouseOn()" onmouseout = "mouseOff()"> Move the cursor over the text to see it change </h1>
You most likely just need to use fontSize and fontFamilly to make this work
function mouseOn() {
...
document.getElementById("text").fontSize = "22px";
document.getElementById("text").fontFamilly = "Font Familly";
}
and then revert it on mouseOff:
function mouseOff() {
...
document.getElementById("text").fontSize = "initial font size";
document.getElementById("text").fontFamilly = "initial familly size";
}
In your css, you can write
#text {
position: auto;
color: blue;
}
#text.changed {
position: fixed;
left: 300px;
color: green;
font-size: 20px; /* here goes your font size */
font-family: sans-serif; /* here goes your font family */
}
Don't forget to make sure you have positioned #text's parent (e.g. position: relative), otherwise positioning on #text won't work.
/* text's-parent { position: relative } */
/* #text.changed { ...the styles you need } */
Then, in js
function mouseOn() {
document.getElementById("text").classList.add('.changed');
}
function mouseOff() {
document.getElementById("text").classList.remove('.changed');
}

Unable to add hover effect to a tag when colours of the a tag are already managed using javascript?

I have a website (https://lunarcreator.uk). I have made a navbar for it which changes beyond a certain y offset (> & < 100) so that it is clear on the background and content during scrolling.
I have the following javascript to do this:
const logo = document.querySelector('#pronav')
const about = document.querySelector('#about')
const log_text = document.querySelector('#log_text')
const link1 = document.querySelector('#link1')
const link2 = document.querySelector('#link2')
const link3 = document.querySelector('#link3')
const getOffset = () => {
if(window.pageYOffset > 100){
logo.style.backgroundColor = 'white';
logo.style.transition = 'background .2s ease-out';
log_text.style.color = 'black';
link1.style.color = 'black';
link2.style.color = 'black';
link3.style.color = 'black';
}
if(window.pageYOffset < 100){
logo.style.backgroundColor = 'rgba(0,0,0,0)';
logo.style.transition = 'background .2s ease-out';
log_text.style.color = 'white';
link1.style.color = 'white';
link2.style.color = 'white';
link3.style.color = 'white';
}
}
window.addEventListener('scroll', getOffset)
the const link_n refers to the specific a tag in the navbar. However, in adding this change on scroll, i have lost the functionality of the a tags having a hover effect on scroll. I have tried specifying the hover in css using :hover but this does not work. How could i go about fixing that?
Thanks for your time. (i have extremely little javascript knowledge so i think this was the best place to come for answers)
It would be much better just to add class to your header after scroll.
let header = document.querySelector('.header');
const getOffset = () => {
if(window.pageYOffset > 100){
header.classList.add('fixed');
}
else {
header.classList.remove('fixed');
}
}
window.addEventListener('scroll', getOffset)
And than edit styles based on header class.
.header a {
color: #FFF;
}
.header.fixed {
background: #fff;
}
.header.fixed a {
color: #000;
}
.header.fixed a:hover {
color: blue;
}
Here is the fiddle: https://jsfiddle.net/oLtvjwhe/
Edit: Avoid using !important which Allan suggested.
Even w3schools say it at the bottom "Tip: It is good to know about the !important rule, you might see it in some CSS source code. However, do not use it unless you absolutely have to." And in this case you don't need !important.
Use the CSS The !important Rule https://www.w3schools.com/css/css_important.asp
Like:
.menu a:hover,
.show-menu-btn:hover,
.hide-menu-btn:hover {
color: #AEC6CF !important;
}
Hope it works.
consider targeting the parent class #pronav.
Then, simply add a fade-to-white class to it:
const FADE_TO_WHITE = 'fade-to-white'
const pronav = document.querySelector('#pronav')
const getOffset = () => {
window.pageYOffset > 100
? pronav.classList.add(FADE_TO_WHITE)
: pronav.classList.remove(FADE_TO_WHITE)
}
then target the children with css:
#pronav.fade-to-white a {
color: black;
}
#pronav a {
color: white;
}
#pronav.fade-to-white a:hover {
color: blue; /* change this */
}
/* continue like this */

Display a message once (like a cookie consent) on first visit

I'm building a website and am trying to display a message at the top of the page (inside the header) so it only appears once on every visit/session. An example of this the 'Book an appointment' green bar at the top of this website:
https://www.tiffany.co.uk
My website is here: https://vitrify.tempurl.host/
I've got as far as having a message appear (orange panel at top of page) but currently it appears every time a page is loaded. I just want it to appear once, just like a cookie consent.
I've spent hours looking for a solution but, as I'm not a programmer, I'm struggling. Any help would be much appreciated.
Here's the HTML:
function myFunction() {
var x = document.getElementById("topDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
.topDIV {
color: #000000;
font-weight: 300;
font-size: 15px;
}
.topDIV a:link, .topDIV a:visited {
color: #000000!important;
font-weight: 500;
letter-spacing: -0.3px;
line-height: 1.2 ;
}
span.topDIV {
}
.topDIV a:hover {
border-bottom: 1px solid rgba(0,0,0,0.50) !important;
display: inline-block;
}
.button-x {
position: relative;
float: right;
top: -5px;
background:none;
border:none;
color:rgb(0,0,0) ;
cursor: pointer;
vertical-align: 0px;
}
.button-x:before {
font-family: 'Times';
content: "X";
font-size:30px;
vertical-align:0px;
opacity:0.5;
}
.button-x:hover {
opacity:1!important;
}
<span class = "topDIV">Welcome to <em>Vitrify</em>. Following in the finest traditions of vitreous enamelled jewellery. Find out more.</span><button class = "button-x" onclick="myFunction()"></button>
As mentioned above you need to use localStorage to solve your problem.
Need to know when page is loaded
Get value from the localStorage
Add event to the button (i removed the onclick event from the html for a cleaner solution)
After click set value for localStorage and hide item
If localStorage have value, hide the element
working example
Javascript
document.addEventListener('DOMContentLoaded', function () {
const topDiv = document.querySelector('.topDIV');
const buttonX = document.querySelector('.button-x');
// Get value from localStorage when open the page
const lS = localStorage.getItem('first-visit');
// Add button 'click' event
buttonX.addEventListener('click', () => {
// Set value to the localStorage
localStorage.setItem('first-visit', false);
// hide DOM element
topDiv.style.display = 'none';
});
// This does not check on the first visit to the page
// If localStorage have value, hide DOM element
if (lS) topDiv.style.display = 'none';
});
Html
<span class="topDIV"
>Welcome to <em>Vitrify</em>.Following in the finest traditions of
vitreous enamelled jewellery.
Find out more.
</span>
<button class="button-x"></button>
You can add a flag "showTopMessage:true" in your local storage or session storage based on one time msg to user or every time he visits. respectively.
On Cross/close icon click set the flag "showTopMessage:false".
const showTopBar = "SHOW_TOP_BAR";
const[showTopBar,setShowTopBar] = useState(true);
useEffect(()=>{
const saveState = localstorage.getItems(showTopBar);
if(saveState) setShowTopBar(saveState);
else localstorage.setItem(showTopBar, true);
},[]);
const handleTopBarClose = () => {
setShowTopBar(false);
localstorage.setItem(showTopBar, false);
}
return(
<div>
{
showTopBar && <TopBarComponent onClose={handleTopBarClose}/>
}
</div>
)

how to stop a sound when an animation ends

I have very little experience in coding in general. But I've somehow managed to get this far with this, and I'm stuck on the very last thing.
This is for a Twitch alert, I'm doing this through 'Stream Elements'
The thing I'm having issues with is stopping the sound once the typing letters have fully appeared, I have no idea how to do this. Is it even possible?
I Forgot to mention, the Typekit links are intentionally broken, as I didn't want to share the link (Since I'm assuming they're all unique and based off your adobe account)
$(document).ready(function() {
var timer, fullText, currentOffset, onComplete, hearbeat = document.getElementById('heartbeat');
heartbeat.play();
function Speak(person, text, callback) {
$("#usernamean-container").html(person);
fullText = text;
currentOffset = 0;
onComplete = callback;
timer = setInterval(onTick, 120
);
}
function onTick() {
currentOffset++;
if (currentOffset == fullText.length) {
complete();
return;
}
var text = fullText.substring(0, currentOffset);
$("#message").html(text);
}
function complete() {
clearInterval(timer);
timer = null;
$("#message").html(fullText);
onComplete()
;
}
$(".box").click(function () {
complete();
});
Speak("{{name}}",
"{{name}} Is now a Witness",
)
//get data from the 🤟 StreamElements 🤟 data injection
const name = '{{name}}';
// vanilla es6 query selection (can use libraries and frameworks too)
const userNameContainer = document.querySelector('#username-container');
// change the inner html to animate it 🤪
userNameContainer.innerHTML = stringToAnimatedHTML(name, animation);
/**
* return an html, with animation
* #param s: the text
* #param anim: the animation to use on the text
* #returns {string}
*/
function stringToAnimatedHTML(s, anim) {
let stringAsArray = s.split('');
stringAsArray = stringAsArray.map((letter) => {
return `<span class="animated-letter ${anim}">${letter}</span>`
});
return stringAsArray.join('');
}
heartbeat.pause();
heartbeat.currentTime = 0;
});
#import url(#import url("https://use.typekit.net/.css");
.awsome-text-container {
font-family: typeka, sans-serif;
font-size: 42px;
font-weight: 400;
}
.image-container {
margin: auto;
display: table;
}
.text-container {
font-family: typeka, sans-serif;
font-size: 26px;
color: rgb(204, 10, 33);
text-align: center;
margin: auto;
text-shadow: rgba(0, 0, 0, 0.5) 1px 1px 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="heart" class="heart">
<audio id="heartbeat" src="https://cdn.discordapp.com/attachments/135995830279733248/733547597305741332/typewriters.mp3" preload="auto"></audio>
<link rel="stylesheet" href="https://use.typekit.net/.css">
<div class="text-container">
<div class="image-container">
<img src="https://media.tenor.com/images/83d6a5ed40a24164dfe1e4e19fad23d9/tenor.gif">
</div>
<div>
<div class="awsome-text-container">
<span id="message"></span>
<br>
</div>
</div>
</div>
Hello and welcome to Stack Overflow!
I have seen messier code and was therefor disappointed ;-). Regarding your question:
Main problem would be that you have a typo in your code and you call the heartbeat.pause(); in the complete method and not at the end of script (as this would be called independently of the completion of the animation).
Typo:
hearbeat = document.getElementById('heartbeat');
Changed method:
function complete() {
clearInterval(timer);
timer = null;
$("#message").html(fullText);
heartbeat.pause();
heartbeat.currentTime = 0;
}
and remove the lines from the bottom of your script.

How to generate CSS variable values to a new stylesheet

I'm working on a project in which a user can select colors from a color input and create their own theme dynamically using CSS variables. I'd like the user to be able to download the entire CSS file with the values they selected.
My issue: The CSS file downloaded doesn't display the actual color values, but shows the variable name.
NOT WANTED
pre[class*="language-"] {
background: var(--block-background);
}
instead of
WANTED OUTPUT
pre[class*="language-"] {
background: #0D2831;
}
I know I can get CSS property values by doing the following.
const styles = getComputedStyle(document.documentElement)
const value = String(styles.getPropertyValue('--block-background')).trim()
I figured that I would create a function that loops through all my CSS variables and grabs the corresponding property values and then adds them to a new stylesheet for the user to download, but I got lost along the way. I currently have two CSS files, a main.css and a prism.css. The main.css file holds the page styling and all CSS variables within the root. The prism.css file contains the theme in which I want the user to be able to download.
I'm trying to find a way to create a new stylesheet that contains everything within the prism.css file but has the actual color hex code instead of the CSS variable name as a value to the given CSS property.
Index.js
import { colors } from './colorHelper'
const inputs = [].slice.call(document.querySelectorAll('input[type="color"]'));
const handleThemeUpdate = (colors) => {
const root = document.querySelector(':root');
const keys = Object.keys(colors);
keys.forEach(key => {
root.style.setProperty(key, colors[key]);
});
}
inputs.forEach((input) => {
input.addEventListener('change', (e) => {
e.preventDefault()
const cssPropName = `--${e.target.id}`;
document.styleSheets[2].cssRules[3].style.setProperty(cssPropName, e.target.value)
handleThemeUpdate({
[cssPropName]: e.target.value
});
console.log(`${cssPropName} is now ${e.target.value}`)
});
});
const cssRules = document.styleSheets[2].cssRules;
for (var i = 0; i < cssRules.length; i++) {
// Finds css variable names
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/
let cssVariables = cssRules[i].cssText.matchAll(regexp)
cssVariables = Array.from(cssVariables).join()
console.log(cssVariables)
}
colorHelper.js
const colorSelect = {
'Line Highlights': {
'highlight-background': '#F7EBC6',
'highlight-accent': '#F7D87C'
},
'Inline Code': {
'inline-code-color': '#DB4C69',
'inline-code-background': '#F9F2F4'
},
'Code Blocks': {
'block-background': '#0D2831',
'base-color': '#5C6E74',
'selected-color': '#b3d4fc'
},
'Tokens': {
'comment-color': '#93A1A1',
'punctuation-color': '#999999',
'property-color': '#990055',
'selector-color': '#669900',
'operator-color': '#a67f59',
'operator-background': '#FFFFFF',
'variable-color': '#ee9900',
'function-color': '#DD4A68',
'keyword-color': '#0077aa'
}
}
const colorNames = []
const colors = {}
Object.keys(colorSelect).map(key => {
const group = colorSelect[key]
Object.keys(group).map(color => {
colorNames.push(color)
colors[color] = group[color]
})
})
export { colorSelect, colorNames, colors }
prism.css
pre[class*="language-"],
code[class*="language-"] {
color: var(--base-color);
font-size: 13px;
text-shadow: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::selection,
code[class*="language-"]::selection,
pre[class*="language-"]::mozselection,
code[class*="language-"]::mozselection {
text-shadow: none;
background: var(--selected-color);
}
#media print {
pre[class*="language-"],
code[class*="language-"] {
text-shadow: none;
}
}
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
background: var(--block-background);
}
:not(pre) > code[class*="language-"] {
padding: .1em .3em;
border-radius: .3em;
color: var(--inline-code-color);
background: var(--inline-code-background);
}
/* Tokens */
.namespace {
opacity: .7;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: var(--comment-color);
}
.token.punctuation {
color: var(--punctuation-color);
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: var(--property-color);
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: var(--selector-color);
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: var(--operator-color);
background: var(--operator-background);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: var(--keyword-color);
}
.token.function {
color: var(--function-color);
}
.token.regex,
.token.important,
.token.variable {
color: var(--variable-color);
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* Line highlighting */
pre[data-line] {
position: relative;
}
pre[class*="language-"] > code[class*="language-"] {
position: relative;
z-index: 1;
}
.line-highlight {
position: absolute;
left: 0;
right: 0;
padding: inherit 0;
margin-top: 1em;
background: var(--highlight-background);
box-shadow: inset 5px 0 0 var(--highlight-accent);
z-index: 0;
pointer-events: none;
line-height: inherit;
white-space: pre;
}
I have three stylesheets.
style.css holds the CSS variables in the root
normalize.css
prism.css contains the styles for syntax highlighting. This is the stylesheet I would like the user to download, but I would like to provide them with the actual hex values for each variable and not the variable name for the CSS property.
Stylesheet order in my HTML
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css"
integrity="sha256-WAgYcAck1C1/zEl5sBl5cfyhxtLgKGdpI3oKyJffVRI=" crossorigin="anonymous" />
<link href="./themes/prism.css" rel="stylesheet" />
EDIT
I attempted to loop through the stylesheet and grab the CSS variable names, but some of them returned as an empty string.
This is what I did
const cssRules = document.styleSheets[2].cssRules;
for (var i = 0; i < cssRules.length; i++) {
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/
let cssVariables = cssRules[i].cssText.matchAll(regexp)
cssVariables = Array.from(cssVariables)
console.log(cssVariables)
}
This was the result in the console
var(--base-color)
var(--selected-color)
<empty string>
var(--block-background)
var(--inline-code-color)
<empty string>
var(--comment-color)
var(--punctuation-color)
var(--property-color)
var(--selector-color)
var(--operator-color)
var(--keyword-color)
var(--function-color)
var(--variable-color)
<empty string>
var(--highlight-background)
I then attempted to chain .replace() after the trim() but that didn't seem to work either.
You can download the file as text then find and replace the variables.
For example:
var s = `pre[class*="language-"] {
background: var(--block-background);
}`
const variables = {"block-background":"#0D2831"};
Object.keys(variables).forEach(key => {
s = s.replace("var(--"+key+")", variables[key]);
});
console.log(s);
You are getting empty strings from css rules that do not have var(--something) in them. Like
#media print {
pre[class*="language-"],
code[class*="language-"] {
text-shadow: none;
}
}
which gives you the first empty string.
You are missing var(--operator-background) because matchAll() actually doesn't do what you expect. It does
returns an iterator of all results matching a string against a regular expression
but the regular expression you have yields only one result. So you need to add g flag to it
/(?:var\(--)[a-zA-z\-]*(?:\))/g
mozselection... Hmm... Not sure, but shouldn't it be -moz-selection?
The full loop for replacements can look like this:
const updated_rules = [];
for (var i = 0; i < cssRules.length; i++) {
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/g;
let updated_rule = cssRules[i].cssText;
let cssVariables = updated_rule.matchAll(regexp);
cssVariables = Array.from(cssVariables).flat();
for (const v of cssVariables) {
updated_rule = updated_rule.replace(v, colors[v.slice(6, -1)]);
}
updated_rules.push(updated_rule);
}
console.log(updated_rules);
It's an ugly code, and should be refactored, but...
Why would you access css through document.styleSheets anyway? It's harder than just replacing strings in a css-file and for one thing, I'm not sure if you whould be able to access ::-moz-selection rule on Chrome, and in turn ::-webkit-selection on Firefox

Categories

Resources