I'm showing a triangle next to some text inside of a container with display:flex. The text's width is not known at design time. The browser will calculate the width needed for it upon rendering. I've provided code below which highlights my scenario.
The issue I'm encountering:
On initial render .triangle-two's position is not correctly determined. The browser appears to not know the width of .text quite yet and so it incorrectly positions .triangle-two until a second rendering pass occurs. Just a moment after rendering .triangle-two shifts to its correct position.
By contrast, .triangle-one does not exhibit this issue at all. I presume that this is because .triangle-one is rendered as text, and thus in the same pass as .text where as .triangle-two is rendered at a different point-in-time making it ineligible for the proper positioning.
Of note, if I apply justify-content: flex-end to .container then this issue does not occur because .triangle-two is positioned first and then .text. So, it's a non-issue when going the other direction.
Is this a common problem? Are there any more elegant solutions?
Note: I'm unable to reproduce the issue with my example provided, but I'm unsure why. I feel confident that this example highlights my issue, but perhaps it's also dependent on page initialization.
* {
box-sizing: border-box;
}
.container {
height: 48px;
display: flex;
flex: 1;
align-items: center;
padding: 8px;
}
.text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.triangle-one {
transform: scale(1, .5);
}
.triangle-two {
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid;
}
<div class='container'>
<div class='text'>
Dynamic text
</div>
<div class='triangle-one'>▼</div>
<div class='triangle-two'></div>
</div>
Ended up figuring this out the next day.
The issue is that I have no text on the page on initial load and then append a bunch of views to the page which have text on them. I'm also using a custom font face.
Since there's no text on the page on initial load - the font face isn't loaded when the views are appended. So, the text shifts around once its font loads causing its shape to change. Then, the triangle next to it needs to reposition.
Related
Im not quite sure how to adress this problem because its solely happening on the mobile chrome browser.
The Problem:
So as you can see on the image there are gaps around the divs where the background is shining trough. The setup of the code is the following:
<div className={classNames(
scss[timeline-item},
scss[inProgress]
)}
>
<img
className={scss.icons}
src={require(`../../../../assets/images/icons/${icon}.png`)}
alt={icon}
/>
</div>
class of the Div:
.timeline-item{
border: white;
flex: 1;
background: url(../../../../assets/images/iconBgSmall.png) repeat-y center;
display: flex;
justify-content: center;
align-items: center;
background-color: #b3b3b3;
>
(Note here when border is set to 0 then i get the same error in the desktop version of chrome, so i set it to white).
When a step is done an additional class gets rendered into the dom of div:
.done {
background-color: black;
}
.inProgress {
background-color: green;
}
Image as Background
to see the image click on it to open in new window (transparent/white)
So as you can see the idea is to use the background color to show the actual state of the timeline. The background image of the div is way bigger than the div itself so it cant be because of the image size.
Already tried:
content: ' ';
border: 0;
Removing box shadows (even tough it doesnt have one).
Negative margins
outline: 0
Removing all the background colors would work but then my functionality is gone.
HTML/CSS Snipped
This is basically the exact code i took and then let it be mapped with mockup data. As you can see here nothing is happening so i dont understand where this error can come from.
https://codepen.io/anon/pen/EeOZVN
Hope somebody can help!
Thanks in advance
(I've tried searching for this but can't seem to describe it correctly--if this answer exits, please point me in the right direction!)
I'm playing around with some css rules. I wanted to make a specific, secondary 2px-wide border on a pseudo-element appear around nav anchors in the header, which open a modal and blur an absolutely-positioned background image div #bg, which sits as such:
<body>
<div id="#bg"></div>
<header id="global-header">
<nav>...</nav>
</header>
</body>
Since I wanted to transition the blur effect, I added translate3d(0,0,0) to #bg, which smoothed the fps by galvanizing the GPU for hardware accelerated processing of CSS. It worked! ...Until I noticed that the vertical (left & right) borders for the links had inconsistent widths across the nav. They were each set at 2px, but every other one looked 1.5(??)px wide. It took me a minute to narrow down why, which ultimately was because of the translate3d transformation. I took screenshots, but I centered and moved the pseudo-elements with border-left: 2px below the header (the effect persisted), and I removed the background image itself so the effect would be easier to see. Here they are:
Inconsistent 2px calculation (with translate3d(0,0,0) on #bg)
Consistent widths (without translate3d transform on #bg)
And for reference, here's the code for the left-bordered pseudo-elements:
#global-header nav ul li a:before {
content: '';
position: absolute;
display: block;
top: 100%;
left: 50%;
height: 100%;
width: 0;
border-left: 2px solid gray;
background-color: transparent;
}
I know that translate3d creates as well as solves a possible host of issues from my searches--but why is this happening? Does it have anything to do with "subpixel calculations"? And why would these calculations render inconsistently throughout the page with hardware acceleration, on something I would assume is hard to mess up?
Edit: So, even without translate3d, the problem-lines flicker to a smaller width when the blur transitions (seen in the code from screenshots) are triggered, and I can reproduce the original issue without translate3d if I add backface-visibility: hidden to the pseudo-element itself. This could hint at general pixel rounding issues, with specific properties as triggers only being a symptom.
After further fiddling, answering my own question: This is not caused caused by hardware acceleration, which was my revised suspicion. Though the use of these effects showcased the problem in my particular case, I was able to recreate a version of my issue without them.
By removing transform3d from the #bg element:
#bg {
.
.
.
/* transform: translate3d(0,0,0); */
}
And, without the backface-visibility property as well, I added some width to the pseudo-element in order to see what these borders would normally look like:
#global-header nav ul li a:before {
content: '';
position: absolute;
display: block;
/* top: 100%; */
/* left: 50%; */
height: 72px;
width: 1px;
border: 2px solid black;
/* backface-visibility: hidden; */
/* border-left: 2px solid black; */
background-color: transparent;
/* transition: height .2s ease; */
}
Duh: I should have expected the result, since earlier I had tried to use the element itself (by making it 1-2px wide and coloring it) instead of border-left, which at the time seemed to fix the issue. Of course, when I did it this time using the above css, the base problem reappeared.
Though I still don't know why the aforementioned properties showcased the problem with border-left as well, addressing this might be too sporadic/situation-dependent to field here, and likely still has more to do with browser rendering than anything else.
Anyway, my question was why transform3d caused this effect, and the answer is, at least in this case, it didn't--it just made it more obvious.
I have an annoying issue with the html layout of a form. I cannot really change the general setup, since it is part of a huge framework. But I have to "move" a button to a more suitable location. I am close, but not happy with the solution so far. Maybe you can give me some idea in this. Here is a dramatically simplified version to demonstrate my approach:
I have two container divs, top and bottom.
The top container shows a button on the left side. That button is fixed, but can have a different width due to the translation of its label.
The bottom container holds lots of stuff. Amongst that a second button at its top which works fine, but looks wrong. I want to optically move it into the top container, since there is a logical connection to the button in there. Sure, really placing it in there would be the correct solution, but I currently cannot do that. Instead I use a fixed position which works fine, except for the horizontal placement. I have to decide how far pushed from the left to place the button, so that it certainly does not overlap the first button in the container. I obviously have to consider all translations, the result works, but depending on the first buttons label I have an annoying horizontal gap between the two buttons.
I tried to use a pseudo element (::before) on the second button to help with the layout. Since when rendering the view I obviously have the translated label of the first button I can copy that into some property of the second button and use that property in my css to fill a before pseudo element of the second button which has exactly the same length as the first button. That is what is shown in the code example posted below.
What I completely fail to do is to place that pseudo element such that is it left in the top container (so exactly below the first button). The idea is to indirectly place the second button that way. Looks like this is not possible, obviously. But since I am a bloody beginner in markup and styling I thought it might be worth asking here...
Below is some drastically stripped down code to demonstrate my approach.
I create a jsfiddle for you to play around with. Here is the code:
HTML:
<div id="top-container">
<button>multilingual button text</button>
</div>
<div id="bottom-container">
<h2>
Some title opening the bottom container
<span class="into-top-container">
<button id="place-me" reference-text="multilingual button text">button to be placed</button>
</span>
</h2>
<p>Some content</p>
<p>Some content</p>
<p>Some content</p>
</div>
CSS:
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
div {
margin: 0;
padding: 5px;
}
button {
margin: 0;
padding: 5px;
white-space: nowrap;
}
div#top-container {
width: 100%;
border: 1px solid green;
}
div#bottom-container {
width: 100%;
border: 1px solid blue;
}
#place-me {
position: fixed;
top: 0;
left: 400px;
margin: 5px;
background: yellow;
}
#place-me::before {
z-index: 0;
/*visibility: hidden;*/
position: absolute;
content: attr(reference-text);
margin: 0 5px;
padding: 0;
background: gold;
right: 100%;
}
Notes:
that in the above code the second button is placed with left: 400px;. That is more or less what I want to change. But obviously left: 0 is not correct...
the visibility css rule for the pseudo element is currently commented out for demonstration purpose
keep in mind that the second button is *not* contained inside the top container, but actually logically below the title of the bottom container. The goal is to move it optically up into the top container which already is where close to what I want. Except for the horizontal alignment...
Upon request here is a screenshot:
It is taken from the fiddle I posted above. I added the red ellipse which shows what element pair I want to move and the left pointing arrow indicating where I want to move that too. I want to move it exactly that far, that the two tests "multilingual button text" are exactly placed on top of each other, but without specifying an explicit left placement obviously. That is why the pseudo element exists: as a dummy placeholder. I would then hide that pseudo element and have the second button placed exactly right of the first button, regardless of how long the translated text in there is.
So the final result should like like that:
OK, I invested some more time, since this issue popped up again after a regression in our code and I found, as often after allowing some time to pass, a logical and relatively clean solution:
I use the same stripped down code to for demonstration purposes.
The jsfiddle is based on the one provided in the question itself.
HTML: no real change, except for the reference-text having moved from button to container, for the why see below:
CSS:
* {
font-size: 12px;
font-weight: normal;
font-family: Arial;
}
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-size: 12px;
font-weight: normal;
}
span,
div {
margin: 0;
padding: 5px;
}
button {
margin: 0;
padding: 5px;
white-space: nowrap;
}
div#top-container {
width: 100%;
border: 1px solid green;
}
div#bottom-container {
width: 100%;
border: 1px solid blue;
}
span.into-top-container {
position: fixed;
top: 0;
left: 0;
pointer-events: none;
border: 1px solid transparent;
}
span.into-top-container::before {
visibility: hidden;
content: attr(reference-text);
position: relative;
margin-right: 5px;
padding: 5px;
border: 2px solid;
background: gold;
}
#place-me {
background: yellow;
pointer-events: all;
}
The basic change in strategy: it is the container holding the button to be placed that has to be positioned in a fixed manner, not that button itself (so the <span class="into-top-container">)! That allows to use the pseudo before element, now also anchored to that container, not the button, to take the space as required without actually getting part of the button itself.
Since that container is now place over the original multilingual button that one is not clickable any more. That issue is fixed by a css pointer-events set to none for the container and set to all for the placed button again. That makes the container itself simply ignore all events (clicks) and have them passed to the original button beneath.
I had to make sure that the font used inside the pseudo element is style exactly like the original multilingual button. That actually makes sense, since the font styling defines the actual width used by that button, so the actual width used by the pseudo element should be defined in exactly the same manner. In the example above I forced that by simply setting all elements font style rules to some fixed values (the initial * {...} in the CSS code). That can obviously also be done right inside the css rules for the pseudo element itself. I chose the more simple and brute variant here to keep the code clean.
Here's a jsFiddle with my situation demoed: http://jsfiddle.net/SFrbZ/4/
Basically, I want to have input fields in table cells and have the inputs set to a fixed height and font-size. What's happening now is that users are able to hover over or click on the input and using the mouse wheel can scroll the text up and partially out of frame. Highlighting the text also allows you to move it up. The following code shows the barebones of this issue as well:
HTML:
<input class="scroll" type="text" value="1"></input>
CSS:
.scroll {
display: table-cell;
width: 38px;
height: 8px;
font-size: 11px;
color: Black;
font-family: Calibri;
text-align: center;
background-color: rgb(182, 231, 201);
}
Oddly enough, this is only occuring on Firefox and not Chrome, IE, or Safari. As you can see in the jsFiddle, increasing the height of the field (or lowering the font-size) solves the problem, but this is not a viable solution for me.
I've tried a number of alterations in an attempt to fix it but have come up dry. Messing with overflow, line-height, padding, margins, display type, etc. and nothing seemed to do the trick. Any pointers or suggestions would be greatly appreciated!
Your best option is probably to install a Javascript handler for scroll events, on elements of class .scroll, which simply swallows the event and returns false -- this will prevent the element from being scrolled by any means, which should solve the problem as stated. This fiddle, using jQuery, demonstrates the solution, and the meat of it is as follows:
$(document).ready(function() {
$('.scroll').scroll(function(e) {
e.preventDefault();
return false;
});
});
Without jQuery, the solution is still feasible by means of window.addEventListener &c., but jQuery makes it so much simpler that, if you're not already using that library in your project, I'd recommend adding it just for this purpose.
The easiest solution is to change the line-height property of the .scroll css class to match the height. Using you're example:
.scroll {
display: table-cell;
width: 38px;
height: 8px;
line-height: 8px;
font-size: 11px;
color: Black;
font-family: Calibri;
text-align: center;
background-color: rgb(182, 231, 201);
}
The issue is that the text technically doesn't fit in that box. Text with a height of 11px usually has a couple of pixels on top and bottom as 'padding' to make it so that multi-line text has spacing between the lines. As a result, it appears the text fits, but it doesn't actually.
I'm writing a page that looks code wise like
<div class="green">
<span class="orange">s1</span>
<span class="orange">s2</span>
</div>
but that should be formated via CSS like:
The surrounding black frame shows the full page in the browser. (Think of <body></body>)
The red frame is a fixed width and fixed hight basically empty space that should be added by the CSS .green:before (I'm using it's ability to format it's borders for a visual effect)
The green frame shows the real content that should be as wide as necessary to contain both <span> in one line
The blue frame should be created by the CSS .green:after, has a fixed height and should take up all the space till the right border of the page - i.e. it must have a variable width.
Required browsers are the modern ones (Firefox, Chrome, Safari, Opera) in recent versions. No need to take care of IE. Mobile browsers would be great, though.
How can I achieve that? (All my attempts failed sooner or later...)
A jsFiddle with this example code is at http://jsfiddle.net/X2MDG/
I'm afraid that there is no way to satisfy all your constraints. The main things that don't seem to have a CSS solution are:
Controlling the width of just the green bit can't be done without affecting the width of the red :before and blue :after content. As you mention in the comments to the question, using a different DOM structure is not an option.
The blue (:after) content should take up all space not needed by the green (main) content.
The fixed height of red/blue may require some clearing on the elements below the entire div.
So, as far as I could tell, the question as you asked it doesn't have a 100% satisfying answer. Either way, here's the code I came up with researching this problem, perhaps it can help you or others stumbling on this question. See either this jsfiddle or the code below:
<div id="page">
<div class="green">
<span>Orange 1.</span>
<span>Orange 2. Which can be really wide.</span>
</div>
<p style="clear: both;">Black is the page. Clearing is
needed because the red and blue boxes are not in the
flow but do have quite some height.</p>
</div>
CSS:
div#page {
border: 2px solid black;
width: 80%;
padding: 2px;
}
div.green:before {
content: 'red / before';
border: 2px solid red;
float: left;
display: inline-block;
width: 140px;
height: 200px;
}
div.green {
border: 2px solid green;
}
div.green:after {
content: 'blue / after';
border: 2px solid blue;
display: inline-block;
float: right;
height: 60px;
}
div.green span {
border: 2px solid orange;
}