So we have an email builder that allows the client to create their own custom color schemes. In additon to pre-defined fields we allow them to enter their own custom CSS block to modify their color schemes.
The problem is we NEED to put a parent selector before each rule. So for instance:
p {font-size:12px;}
will need to become
.parent_selector p {font-size:12px;}
Is there anyway to programmatically add these parent selectors to EACH CSS rule? As an example use case let's say this is the custom css provided by the client:
p {font-size:12px; font-weight:bold}
.description {color:#cccccc; line-height:1.2em;}
#header {padding:bottom:12px}
.buttons .button {padding:12px; background:#112233;}
.buttons a {text-decoration:none;}
I would need a parent selector before each rule. I've considered searching for brackets and adding text accordingly but it got too complicated. Another option (which I don't like) is creating a dummy selector and doing a string replace. Here is an example:
.placeholder p {font-size:12px;}
will need to become
.parent_selector p {font-size:12px;}
Thanks in advance!
You could try to inject their code into something like the less preprocessor and compile before sending to the server. or create your own parser to prepend the parent selector to the classes provided. This would probably need work for the different formats that could be input by your users.
edit: on second thought don't leave it to chance. remove all double whitespace characters and you will get a consistent formatting and minification for free.
function addParentSelector( parentSelector, styles ){
return styles.replace(/((?:\s|\n|\t)+)/gm, ' ').replace(/([^{]+)({[^}]+})/gm, function(_, selectors, styles ){
return selectors.split(',').map(function( selector ){
return parentSelector + ' ' + selector;
}).join(',') + styles;
});
}
function compile(){
var res = addParentSelector('.some-parent-selector', document.querySelector('#styles').value );
document.querySelector('#output').innerHTML = res;
}
/* ignore the css here */
textarea {
width: 100%;
height: 6em;
}
pre {
white-space:pre-wrap;
word-wrap:break-word;
}
button {
cursor: pointer;
display: inline-block;
text-align: center;
color: #fff;
line-height: 1;
padding: .6em .8em;
background: #009afd;
-webkit-transition: background 0.15s ease, color 0.15s ease;
-moz-transition: background 0.15s ease, color 0.15s ease;
-ms-transition: background 0.15s ease, color 0.15s ease;
-o-transition: background 0.15s ease, color 0.15s ease;
border: 1px solid #1777b7;
box-shadow: 0 1px 0 rgba(255,255,255,0.3) inset,0 1px 1px rgba(100,100,100,0.3);
border-radius: 3px;
}
button:hover {
color: #fff;
background: #0087de;
}
<textarea id='styles'>
.profile
{
line-height: 2;
padding: 1em;
font-family: sans-serif;
}
.profile__header { background: red; }
.profile__header-heading {
font-size: 2em;
padding: 0;
margin: 0;
}
.profile__header-heading small {
color: rgba(43,44,43,.7);
}
.profile__header-edit {
padding: .5em 2em;
border: .2em solid #3cf;
color: #fff;
background: #3cf;
text-decoration: none;
transition: .2s;
}
.profile__header-edit:hover {
color: #3cf;
background: #fff;
}
.profile__content p {
color: rgba(34,35,34,.7);
line-height: 2;
}
</textarea>
<button onclick="compile()">click me!</button>
<pre id="output"></pre>
edit: there was an issue in the Regex. I was using a [\s|\n|\t] group for space|newline|tab but it should have been a non capture group (?:\s|\n|\t).
This should be more complete. Also please be aware that Array.prototype.map() will fail in IE < 9.
Related
I am trying to make a website where hovering over a misspelling consisting of transposition of two letters corrects it, like so:
var swap = document.querySelector('.swap');
swap.addEventListener('mouseover', swapIn);
swap.addEventListener('mouseout', swapOut);
function swapIn(e) {
e.target.parentNode.firstChild.classList.toggle('shifted-right');
e.target.parentNode.lastChild.classList.toggle('shifted-left');
}
function swapOut(e) {
e.target.parentNode.firstChild.classList.toggle('shifted-right');
e.target.parentNode.lastChild.classList.toggle('shifted-left');
}
body {
font-size: 24px;
}
.swap {
display: inline;
}
span {
-webkit-transition: all 0.3s linear;
-moz-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
}
.shifted-right {
margin-left: 20px;
color: blue;
}
.shifted-left {
margin-left: -25px;
color: red;
}
E<div class="swap" id="swap"><span class="left-swap" id="ls">q</span><span class="right-swap" id="rs">c</span></div>uis me vivit fortunatior?
However, as you can see, the letters don't swap well, and besides, I don't want to calculate the precise margins for each different letter width.
What's a better approach to doing this?
Switching two letters in the same word can be done by calculating their relative position to their parent with the offsetLeft property.
Subtract the values from each other and use Math.abs to keep the integer a positive number. This number is the distance between the two letters. One letter has to go the entire distance to the left and the other the same distance to the right to switch positions. Set the a CSS Variable with the distance so we can pass the calculation to CSS.
In CSS we can use the :hover pseudo selector to set styles on hover and use the CSS Variable to make the proper transition. And instead of targeting the hover on a letter, target the hover on the entire word.
Instead of margin, use transform; this property does not mess with the layout and will only any manipulate the element that is targeted.
const word = document.querySelector('.word');
const [e, a] = word.querySelectorAll('.letter');
const distance = Math.abs(e.offsetLeft - a.offsetLeft);
word.style.setProperty('--distance', `${distance}px`);
.word {
display: inline-block;
padding: 15px;
position: relative;
font-size: 32px;
background-color: #f7f7f7;
border: 1px dashed #d0d0d0;
border-radius: 3px;
cursor: help;
}
.word .letter {
display: inline-block;
color: red;
transition: color 500ms ease-in-out, transform 500ms ease-in-out;
}
.word:hover .letter {
color: green;
}
.word:hover .letter:first-of-type {
transform: translate(var(--distance), 0);
}
.word:hover .letter:last-of-type {
transform: translate(calc(var(--distance) * -1), 0);
}
<span class="word">
App<span class="letter">e</span>r<span class="letter">a</span>nt
</span>
I have one dark division box I want to develop such thing when you click and hold mouse over div one round shape div will transparent and it will show hidden sentence under that dark div.
give that div box a class e.g darkBox then in css
u can also give "active" property for clicking
border-radius can make it round, if u give 50% it will make it circle, if u want corner edges round or curved u can give values less than this
.darkBox:hover{
background-color: transparent;
border-radius: 50%;
}
I hope this helps ,if not can you please tell me what u exactly require
Key point:
A round shape can easily be made by using border-radius: 50%.
The pseudo-class :hover is what activates the alternate state.
The pseudo-class :before (and :after) can insert into an element some text.
The extra fading effects were done with transition.
.orb {
font-size: 3em;
border: 2px solid black;
border-radius: 50%;
height: 1.5em;
width: 1.5em;
text-align: center;
cursor: pointer;
background-color: black;
}
.orb:before {
content: '\2620';
transition: opacity 3.5s ease-in, color 4s linear;
opacity: 0;
color: transparent;
}
.orb:hover:before {
content: '\2620';
opacity: 1;
color: white;
}
.cap:after {
content: '';
transition: opacity 3.5s ease-in, color 4s linear;
opacity: 0;
color: transparent;
}
.orb:hover .cap:after {
content: 'The skull and crossbones is actually a font character';
opacity: 1;
color: red;
font: 400 16px/.3 'Palatino Linotype';
white-space: nowrap;
}
<figure class="orb">
<figcaption class="cap"></figcaption>
</figure>
Hello guys so what I am trying to do is to animate a buttons background color using jquery.
$(document).ready(function(){
$('button').mouseenter(function(){
$('button').animate({
background-color:"blue"},1000);
});
$('button').mouseleave(function() {
$('button').animate({
background-color:"white"},1000);
});
});
What did I do wrong? And one more thing, can you explain like for dummies? :D
P.S. : I am using bootstrap
jQuery can't natively animate colours. You need to use a plugin, like this one: http://www.bitstorm.org/jquery/color-animation/.
Better than that you can use CSS transitions, assuming you don't need to support IE9 or lower.
button {
background-color: blue;
transition: background-color 1s;
-moz-transition: background-color 1s;
-webkit-transition: background-color 1s;
/* for prettyness only */
border: 0;
color: #CCC;
border-radius: 5px;
padding: 10px;
}
button:hover {
background-color: white;
}
button a {
color: white;
transition: color 1s;
-moz-transition: color 1s;
-webkit-transition: color 1s;
}
button:hover a {
color: blue;
}
<button>Foo bar
</button>
jQuery does not naively support this. Try using the jQuery.color plugin:
<script type="text/javascript" src="http://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
There are a few answers to similar questions, but none that are working for me while still giving me the desired effect, or none that I understand. So any help or guidance would be great
Here's a fiddle: http://jsfiddle.net/csoh1vzb/
Essentially what happens is when you hover over the cells quickly, the mouseleave function doesn't run and I'm left with the active state.
I've "half fixed" this, but it's still not as I would like it to be.
Adding this to mouseenter fixes the problem on the next hover:
$('.cell .hover').fadeOut();
$('.cell span').animate({ "marginTop" : "500px" });
(Not really a fix)
Any help would be great!
The problem is not the not fired mouseleave, the problem you are facing is that the animation takes 400ms (the default animation duration) to complete, which means that the animation is overriding the mouseleave css change directly after it has been applied when you leave the field within say 300ms
To avoid this, you need to stop the animation.
$('.cell span').stop();
$('.cell .hover').fadeOut();
Should do the trick.
As a Sidenote, if you're doing animations with javascript, better change to velocity.js which is far faster than jQuery's animate.
Whenever possible, it is always better to avoid the use of javascript and prefer using css rules.
You can easily replace your html generation and your fade animation using basic html and css, as you can see on this jsfiddle
Writing fully your html :
<a href="" class="cell cell-01" title="ONE">
<div class="hover"><span>ONE</span></div>
</a>
<a href="" class="cell cell-02" title="TWO">
<div class="hover"><span>TWO</span></div>
</a>
And defining most of the rules in your css :
.cell {width: 200px; height: 200px; background: #f00; float: left; display: block; overflow: hidden;}
.cell:hover .hover {
display:inline-block;
opacity: 1;
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.hover {
display:inline-block;
width: 200px;
height: 200px;
background: #000;
text-align: center;
opacity: 0;
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.hover span {display: inline-block; padding: 10px 20px; font: bold 12px arial; font-style: italic; text-transform: uppercase; background: #222; border: 2px solid #fff; color: #fff;}
And you can easily reduce the size of your javascript, making the entire thing more stable and fast.
(function ($) {
$('.cell').on('mouseenter', function (){
var $this = $(this);
$(this).find('span').stop(true, false).animate({ "marginTop" : ($(this).innerHeight() / 2 - 19) + "px" });
}).on('mouseleave', function (){
var $this = $(this);
$(this).find('span').animate({ "marginTop" : "500px" });
});
}(jQuery));
Personally the first answer above is probably simpler and thus a better answer. But I like this because the code seems a bit cleaner overall.
HTML:
<div class="cell"> <span>ONE</span>
</div>
<div class="cell"> <span>TWO</span>
</div>
CSS:
.cell {
width: 200px;
height: 200px;
background: #f00;
float: left;
display: block;
overflow: hidden;
position:relative;
}
.hover {
width: 200px;
height: 200px;
background: #000;
text-align: center;
position: absolute;
top:-200px;
}
.hover span {
display: inline-block;
padding: 10px 20px;
font: bold 12px arial;
font-style: italic;
text-transform: uppercase;
background: #222;
border: 2px solid #fff;
color: #fff;
}
JavaScript:
(function ($) {
$('.cell').on('mouseenter', function () {
$(this).find('span').stop().animate({
"marginTop": ($(this).innerHeight() / 2 - 19) + "px"
});
$(this).find('.hover').stop().animate({
"top": 0
});
}).on('mouseleave', function () {
var $this = $(this);
$(this).find('.hover').stop().animate({
"top": "-200px"
});
$(this).find('span').animate({
"marginTop": "0px"
});
});
}(jQuery));
I understand that an element can change the style of associated elements upon hovering as long as they're within the same divs, but how can the same functionality be achieved when they're all in separate elements such as div, section, article, h1, etc.
I have set up a jsfiddle that consists of a version that works and a version that doesn't. As best, I would like to find out a way to achieve this through CSS only, but if it is an issue that only javascript can solve, that'll be okay.
I've been looking around StackOverflow but there doesn't seem to be an answer to what to do when the elements are within separate elements.
HTML
<h1>This version works fine...</h1>
... <span class="a1">fruits</span> and <span class="b1">vegetables</span>... <span class="a2">apple</span>, <span class="b2">asparagus</span>
<h1>...but how can I get this to work?</h1>
... <div class="div1"><span class="a1">fruits</span> and <span class="b1">vegetables</span></div>... <div class="div2"><span class="a2">apple</span>, <span class="b2">asparagus</span></div>
CSS
.a1, .b1 {
border:1px solid #333333;
padding: 0 1% 0 1%;
text-align: center;
-o-transition: color 0.2s ease-out;
-ms-transition: color 0.2s ease-out;
-moz-transition: color 0.2s ease-out;
-webkit-transition: color 0.2s ease-out;
transition: color 0.2s ease-out;
}
.a2, .b2 {
border:1px solid #dddddd;
padding: 0 1% 0 1%;
text-align: center;
-o-transition: color 0.2s ease-out;
-ms-transition: color 0.2s ease-out;
-moz-transition: color 0.2s ease-out;
-webkit-transition: color 0.2s ease-out;
transition: color 0.2s ease-out;
}
.a1:hover {
border:1px solid red;
color: white;
background-color: red;
}
.b1:hover {
border:1px solid green;
color: white;
background-color: green;
}
.a1:hover ~ .a2 {
border:1px solid red;
color: white;
background-color: red;
}
.b1:hover ~ .b2 {
border:1px solid green;
color: white;
background-color: green;
}
I've found out what the problem is.
Go to your code, fix or take off the lines below from the problematic part
</div>
<div class="div2">
Two problems
1 Closing DIV without a starting part
1 Opening DIV without closing part
See it working here
For jQuery: you can do something like
$(".a1").hover(function () {
$(".a2, .a1").css({"color":"white", "background-color":"red"});
});
See the jQuery example here
Note: If you have the DIV's there for a reason, try the jQuery method
CSS
.a1:hover, .a2.light { /* your css */ }
.b1:hover, .b2.light { /* your css */ }
JAVASCRIPT
var fruits = document.querySelectorAll('.div2 .a2'),
vegets = document.querySelectorAll('.div2 .b2'),
spanf = document.querySelector('.div1 .a1'),
spanv = document.querySelector('.div1 .b1');
spanf.addEventListener('mouseenter', function() {
[].forEach.call(fruits, function(el) {
el.classList.add('light');
});
});
spanf.addEventListener('mouseleave', function() {
[].forEach.call(fruits, function(el) {
el.classList.remove('light');
});
});
spanv.addEventListener('mouseenter', function() {
[].forEach.call(vegets, function(el) {
el.classList.add('light');
});
});
spanv.addEventListener('mouseleave', function() {
[].forEach.call(vegets, function(el) {
el.classList.remove('light');
});
});
DEMO
NOTE Safari doesn't support mouseenter / mouseleave. You can use mouseover / mouseout instead.
If you prefer a solution with jQUERY (it's less to write, but does the same under the hood):
var fruits = $('.div2 .a2'),
vegets = $('.div2 .b2');
$('.div1 .a1').hover(function() {fruits.toggleClass('light');});
$('.div1 .b1').hover(function() {vegets.toggleClass('light');});