I've run into an odd text rendering issue with Firefox. I have a div that is rotated, and another div inside it has it's opacity rapidly changed between 1 and 0.5. This causes any text inside the div to render differently each time the opacity changes - some numbers will shift up or down by a pixel, parts of the text will be thicker or narrower.
As an example, this:
<div class="outer">
<div class="glowyWrapper">
<div class="glowy transparent"></div>
</div>
<p class="someText">1 2 3 4 5 6 7 8 9</p>
</div>
With these styles:
.outer {
transform: rotate(1deg);
width: 300px;
height: 200px;
}
.glowyWrapper {
width: 100%;
height: 10%;
}
.glowy {
width: 100%;
height: 100%;
}
.transparent {
opacity: 0.5;
}
.someText {
font-size: 60px;
font-weight: 800;
text-align: center;
margin: 10px;
}
Adding a bit of javascript to repeatedly add and remove the "transparent" class will cause the rendering issue.
Here is a fiddle demonstrating the issue:
https://jsfiddle.net/projectx593/n01m1jop/10/
I have found a few workarounds, like decreasing the rate the opacity changes, or having it alternate between 0.95 but I'd rather not have to adjust the speed of it if possible, or have the flashing div be always transparent to some degree. Is there a better solution to this?
I found the issue in Firefox version 46.0
Since transform is already there and -moz-backface-visibility: hidden; useless you may use a filter to force FF render calculation, so you cure also the stair effect on edges.
filter: blur(0.1px);/* note that even 0 as value does it */
https://jsfiddle.net/n01m1jop/14/
Related
I am having an understanding problem with the following code:
let myDiv1 = document.getElementById("myDiv1");
alert("Click me to make 'Hello' vanish");
myDiv1.style.height = "0px";
let myDiv2 = document.getElementById("myDiv2");
alert("Click me to make 'World' vanish");
myDiv2.style.height = "0";
.myClass1 {
box-sizing: border-box;
overflow: hidden;
padding-top: 2em;
padding-bottom: 2em;
background-color: yellow;
}
.myClass2 {
box-sizing: content-box;
overflow: hidden;
padding-top: 2em;
padding-bottom: 2em;
background-color: orange;
}
<body>
<div id="myDiv1" class="myClass1">
Hello
</div>
<div id="myDiv2" class="myClass2">
World
</div>
</body>
I understand the behavior of the second (orange) div: It has box-sizing: content-box;, so its height does not include the padding or the borders. Hence, when its height is set to 0, it shrinks basically by the height of the text "World", but the padding is left as-is. Since the padding exceeds the original text height, the text is still visible in the padding. Only that part of padding which is now outside the div (due to the reduced height) becomes invisible (due to overflow: hidden;).
I do not understand the behavior of the first (yellow) div, though. It has box-sizing: border-box;, so its height does include the padding and the borders. Hence, when its height is set to 0, it should shrink to "real" zero height, meaning that the text, the padding and the borders then should be outside the div and thus should be invisible (due to overflow: hidden;).
Can anybody explain why this is not the case and why the first div behaves just like the second div?
P.S. Tested in Firefox and Chrome, both up-to-date (production channel) at the time of writing this.
border-box tells the browser to account for any border and padding in the values you specify for an element's width and height. If you set an element's width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width. This typically makes it much easier to size elements. ref
Here is an example to better ilustrate your issue:
.box {
display: inline-block;
padding-top: 2em;
padding-bottom: 2em;
border: 2px solid blue;
background: linear-gradient(red, red) content-box, orange;
height: 100px;
animation:move 5s linear infinite alternate;
}
#keyframes move{
to {
height:0;
}
}
<div class="box">
World
</div>
<div class="box" style=" box-sizing: border-box;">
World
</div>
The first example is the trivial one where we decrease the height (red area) until 0 and the animation never stop.
In the second case the height include the padding and border so before reaching 0 the content area is already 0 that's why the animation seems to stop because we cannot decrease more than 0 and the border/padding already consumed all the space.
It's logical that when height is equal to 0 both are the same since in the first one we tell the browser that the content area should be 0 (we don't care about padding/border) and in the second case we told the browser to account for the padding/border into the height we specified so we have less room for the content area and since we cannot have less than 0 then its 0.
In other words, you aren't setting the total height that will be split between the content area, padding and border but you are setting a height and the browser is shrinking it as much as possible to include the border and padding.
Related for more examples and details: box-sizing: border-box with no declared height/width
I was reading this article http://semisignal.com/?p=5298 and the author wrote that
"Reflow needs to be triggered before the invisible class is removed in order for the transition to work as expected. "
My questions are :
1) Why does reflow need to be triggered?
2) I understand that we should avoid using reflow, if that is true why is the author suggesting to use reflow in order to make the transition work?
3) Instead of using reflow, is there a different method to make the transition work?
Thank you.
(Effectively: "Why can't I easily use transitions with the display property")
Short Answer:
CSS Transitions rely on starting or static properties of an element. When an element is set to display: none; the document (DOM) is rendered as though the element doesn't exist. This means when it's set to display: block; - There are no starting values for it to transition.
Longer Answer:
Reflow needs to be triggered because elements set to display: none; are not drawn in the document yet. This prevents transitions from having a starting value/initial state. Setting an element to display: none; makes the document render as if the element isn't there at all.
He suggest reflowing because it's generally accepted to hide and show elements with display: none; and display: block; - typically after the element has been requested by an action (tab or button click, callback function, timeout function, etc.). Transitions are a huge bonus to UX, so reflowing is a relatively simple way to allow these transitions to occur. It doesn't have an enormous impact when you use simple transitions on simple sites, so for general purposes you can trigger a reflow, even if technically you shouldn't. Think of the guy's example like using unminified JavaScript files in a production site. Can you? Sure! Should you? Probably not, but for most cases, it won't make a hugely noticeable difference.
There are different options available that prevent reflowing, or are generally easier to use than the method in the link you provided. Take the following snippet for a few examples:
A: This element is set to height: 0; and overflow: hidden;. When shown, it's set to height: auto;. We apply the animation to only the opacity. This gives us a similar effect, but we can transition it without a reflow because it's already rendered in the document and gives the transitions initial values to work with.
B: This element is the same as A, but sets the height to a defined size.
A and B work well enough for fading in elements, but because we set the height from auto/100px to 0 instantly, they appear to collapse on "fade out"
C: This element is hidden and we attempt to transition the child. You can see that this doesn't work either and requires a reflow to be triggered.
D: This element is hidden and we animate the child. Since the animation keyframes give a defined starting and ending value, this works much better. However note that the black box snaps into view because it's still attached to the parent.
E: This works similarly to D but we run everything off the child, which doesn't solve our "black box" issue we had with D.
F: This is probably the best of both worlds solution. We move the styling off the parent onto the child. We can trigger the animation off of the parent, and we can control the display property of the child and animate the transition as we want. The downside to this being you need use animation keyframes instead of transitions.
G: While I don't know if this triggers a reflow inside the function as I haven't parsed it myself, you can just simply use jQuery's .fadeToggle() function to accomplish all of this with a single line of JavaScript, and is used so often (or similar JS/jQuery fadeIn/fadeOut methods) that the subject of reflowing doesn't come up all that often.
Examples:
Here's a CodePen: https://codepen.io/xhynk/pen/gerPKq
Here's a Snippet:
jQuery(document).ready(function($){
$('button:not(#g)').click(function(){
$(this).next('div').toggleClass('show');
});
$('#g').click(function(){
$(this).next('div').stop().fadeToggle(2000);
});
});
* { box-sizing: border-box; }
button {
text-align: center;
width: 400px;
}
div {
margin-top: 20px;
background: #000;
color: #fff;
}
.a,
.b {
overflow: hidden;
height: 0;
opacity: 0;
transition: opacity 3s;
}
.a.show {
height: auto;
opacity: 1;
}
.b.show {
height: 100px;
opacity: 1;
}
.c,
.d {
display: none;
}
.c.show,
.d.show {
display: block;
}
.c div {
opacity: 0;
transition: 3s all;
}
.c.show div {
opacity: 1;
}
.d div {
opacity: 0;
}
.d.show div {
animation: fade 3s;
}
#keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
.e div {
display: none;
}
.e.show div {
display: block;
animation: fade 3s;
}
.f {
background: transparent;
}
.f div {
background: #000;
display: none;
}
.f.show div {
display: block;
animation: fade 3s;
}
.g {
display: none;
}
<button id="a">A: Box Height: Auto</button>
<div class="a">This<br/>Has<br/>Some Strange<br/><br/>Content<br>But<br>That doesn't really<br>Matter<br/>Because shown,<br/>I'll be<br/>AUTO</div>
<button id="b">B: Box Height: 100px</button>
<div class="b">Content For 2</div>
<button id="c">C: Hidden - Child Transitions (bad)</button>
<div class="c"><div>Content<br/>For<br/>3<br/></div></div>
<div style="clear: both;"></div>
<button id="d">D: Hidden - Child Animates (Better)</button>
<div class="d"><div>Content<br/>For<br/>4<br/></div></div>
<div style="clear: both;"></div>
<button id="e">E: Hidden - Child Hidden & Animates</button>
<div class="e"><div>Content<br/>For<br/>5<br/></div></div>
<button id="f">F: Child Has BG & Animates (Works)</button>
<div class="f"><div>Content<br/>For<br/>5<br/></div></div>
<div style="clear: both;"></div>
<button id="g">G: This uses fadeToggle to avoid this</button>
<div class="g">I animate with<br/>JavaScript</div>
<footer>I'm just the footer to show the bottom of the document.</footer>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Here's a code pen that illustrates the code I will place here: https://codepen.io/andrewsunglaekim/pen/MmmxvO
Don't mind the terrible html, I just copied a simple high charts demo.
The Html is simple:
<div class="flexContainer">
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<div class='flexToggle'>Flex it</div>
</div>
Simple chart nested within a flex container.
The CSS:
.flexContainer {
display: flex;
}
#container {
transition: flex 0.5s ease;
flex: 3;
background: red;
}
.flexToggle {
transition: flex 0.5s ease;
flex: 1;
background: green;
}
#container.flexed {
flex: 1;
}
.flexToggle.flexed {
flex: 3;
}
Here's the simple jQuery script that toggles the flexed class:
$(".flexToggle").on("click", function(){
$("#container").toggleClass("flexed")
$(".flexToggle").toggleClass("flexed")
})
I want the chart to resize dynamically with the transitioning flex elements. Everything I've seen is a work around leveraging windows resizing, but I have no event like that in this case. Writing a setInterval to redraw during the transition seems hacky. Is there a configuration piece I'm missing that makes this really simple?
After some research, you can fix the horizontal scaling by simply adding
.highcharts-container, .highcharts-container svg {
width: 100% !important;
}
to the CSS
It works so far on using the contenteditable attribute on the <div> tag with the autogrow feature of a textbox. Also the height transition of it. It all works good, except for one thing, deleting characters, to be specific, a line, will not animate its height, unlike adding new lines. I have still a little knowledge on CSS.
.autogrow {
border: 1px solid rgb( 0, 0, 0 );
padding: 10px;
}
#keyframes line_insert {
from {
height: 0px;
}
to {
height: 20px;
}
}
.autogrow[contenteditable] > div {
animation-duration: 250ms;
animation-name: line_insert;
}
.autogrow[contenteditable] {
overflow: hidden;
line-height: 20px;
}
<div class="autogrow" contenteditable="true"></div>
When I press Shift + Enter, it doesn't animate either, it does well though while pressing Enter. Just the removing of lines and the Shift + Enter key combination while entering a new line is the problem.
How to make it work? Can it be done using pure CSS? Or adding a javascript function for it?
To avoid these issues, I personally use a solution not based on pure CSS animations / transitions which I found always have problems. For example, in your CSS implementation, there is a bounce back effect if using the Enter too fast (you can slow the animation down to see it better).
Moreover, new lines handling is different between browsers, some will add <div><br></div>, some versions of IE add only <br>, etc.
I've never been able to fix all these problems or found an implementation fixing all of these so I decided to not modify at all the behavior of the contenteditable, let the browser do is magic which works and instead, react to what's happening.
We don't even have to worry about keys events like Shift + Enter or events like deletion, etc., all of these are natively handled by the navigator.
I choose instead to use 2 elements: one for the actual contenteditable and one for the styling of my contenteditable which will be the one having height animations / transitions based on the actual height of the contenteditable.
To do that, I'm monitoring every events that can change the height of a contenteditable and if the height of my styling element is not the same, I'm animating the styling element.
var kAnimationSpeed = 125;
var kPadding = 10;
$('div[contenteditable]').on('blur keyup paste input', function() {
var styleElement = $(this).prev();
var editorHeight = $(this).height();
var styleElementHeight = styleElement.height();
if (editorHeight !== styleElementHeight - kPadding * 2) {
styleElement.stop().animate({ height: editorHeight + kPadding * 2 }, kAnimationSpeed);
}
});
.autogrowWrapper {
position: relative;
}
.autogrow {
border: 1px solid rgb(0, 0, 0);
height: 40px; /* line-height + 2 * padding */
}
div[contenteditable] {
outline: none;
line-height : 20px;
position: absolute;
top: 10px; /* padding */
left: 10px; /* padding */
right: 10px; /* padding */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="autogrowWrapper">
<div class="autogrow"></div>
<div contenteditable="true"></div>
</div>
It's kinda hacky, but it works.
First, modify your CSS
.autogrow {
border: 1px solid rgb( 0, 0, 0 );
padding: 10px;
}
#keyframes line_insert {
from {
height: 0px;
}
to {
height: 20px;
}
}
.autogrow[contenteditable] > div {
animation-duration: 250ms;
animation-name: line_insert;
}
.autogrow[contenteditable] {
overflow: hidden;
line-height: 20px;
}
Then add this jQuery that detects Shift + Enter events and appends a div whenever they occur
$(".autogrow").keydown(function(e){
if (e.keyCode == 13 && e.shiftKey || e.keyCode == 13)
{
$(this).animate({height: $(this).height()+20},200);
$(this).append('<div><br></div>');
}
});
And that should work.
Check fiddle https://jsfiddle.net/wx38rz5L/582/
I'm trying to change the background color on a section.
<section id="welcome" class="gradientBlue">
<div class="mainTitle">
<h1>Sdesigns</h1>
<h2>Taking web design to the next level</h2>
<div class="centerArrow">
<i id="0" class="icon-caret-down arrow arrowDown"></i>
</div>
</div>
</section>
The is how it currently looks:
The Idea is when I press the arrow the background changes to another gradient color. I already set this class up. So It should slowly fade-in class "gradientGreen".
.gradientGreen{
background-color:#39b54a;
background: -webkit-gradient(radial, center center, 0, center center, 460, from(#8dc63f), to(#205075));/* Safari 4-5, Chrome 1-9 */
background: -webkit-radial-gradient(circle, #8dc63f, #39b54a);/* Safari 5.1+, Chrome 10+ */
background: -moz-radial-gradient(circle, #8dc63f, #39b54a);/* Firefox 3.6+ */
background: -ms-radial-gradient(circle, #8dc63f, #39b54a);/* IE 10 */
}
I already tried this and many more in Jquery but it always changes instant. I hope anyone can help me.
$('.arrowDown').click(function(e) {
$("#welcome").addClass("gradientGreen");
}
See DEMO.
You can detach the background from the element by creating two separate <div>s with the gradients that are absolutely positioned beneath the target element. Then you can animate with the opacity to switch between these two gradients.
<section id="welcome">
<div class="mainTitle"><!-- your text --></div>
<div id="back1" class="gradientBlue"></div>
<div id="back2" class="gradientGreen"></div>
</section>
#welcome {
position: relative;
}
#back1 {
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
top: 0;
left: 0;
}
#back2 {
position: absolute;
width: 100%;
height: 100%;
z-index: -2;
top: 0;
left: 0;
}
Then change the opacity of the initial background.
$('.arrowDown').click(function (e) {
$("#back1").animate({opacity: 0}, 1000);
});
You might want to take a look at the transition property. It's all CSS3, no jquery needed !
Edit : my bad, as Antony said you can't apply transitions to background gradients.