CSS inverted trapezium when width will differ - css

I need to make the shape below, which will contain some text. Sometimes the text will be longer, sometimes shorter so I can use any fixed widths.
**********
* *
******
This the is code I have - I'm wondering if there's a way I can tag an image on to the beginning and the end of the span. The height won't change so that would probably be the best in terms of cross browser solutions...
<div class="trapizium_holder">
<span id="trapizium"></span>
</div>

One Wrapper Only Needed (IE8+)
This fiddle demonstrates that only a single wrapper is needed. It uses a single pseudo-element to get the angles. The wrapper must either be floated or an inline-block. Here's the code:
HTML
<div class="trapizium">
Test text
</div>
CSS
.trapizium {
position: relative;
float: left; /* wrap the text */
clear: left; /* for demo */
margin: 10px 20px; /* left/right margin will be diagonal width */
/* needs some set height */
font-size: 1em;
line-height: 1em;
padding: .2em 0;
background-color: cyan;
}
.trapizium:before {
content: '';
height: 0;
width: 100%;
position: absolute;
top: 0;
left: -20px; /* stick out into margined area */
z-index: -1; /* make it the background */
border: 20px solid transparent; /* left/right diagonals */
border-top: 1.4em solid cyan;
border-bottom: 0px solid transparent;
}

Fiddle
#trapizium {
border-top: 100px solid blue;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
height: 0;
width: 100px;
}
You may have to absolute position your text into your shapes. This uses borders to make the shape, and has no height.

Related

Sub-Pixels calculated and rendered differently among browsers

The purpose:
I am working on a code similar to this to create a component where an input field has an embedded button:
http://codepen.io/anon/pen/pgwbWG?editors=110
As you can see, the button is positioned absolutely with top and bottom set to 0, to achieve a 100% height element.
Also to note is that the border of the text-input must stay visible and also wrap the button.
To achieve this I added a margin: 1px to the button so that there is (should be) space to display the surrounding text-input red border (usually when the input field content is invalid).
The problem:
is that on Firefox it is (mostly) rendered correctly, while on Chrome (and apparently on the newest Safari) it will have a 1px gap at the bottom of the button.
CSS seems ok but it appears to be a calculation/rounding problem in the rendering, where the bottom or the top margin of the button are not really 1px (can see it inspecting the element).
And also the padding of the input seems to influence in that.
At different zoom-rates it will add or remove 1px of margin to the top or the bottom of the button, resulting in a 1px-gap or in a covered-border.
As I set the button margin to 0px then the bottom margin is fixed but I loose the 1px margin on the top, finishing to cover the red border of the text-input.
The examples:
Probably I am not clear or too verbose in explaining it, so here are some screenshots of the bug, from different zooms on Chrome (note the CSS is always the same):
The solution:
I was not able to find a cross-browser solution.
How to deal with it and get a consistent component?
(no Javascript please)
As you already know, the problem arises from a different approach to subpixel calculus between browsers
In Chrome, for instance, borders can have a fractional size, but margins are handled different (as integers).
I don't have documentation about it from the Chrome team, but it's what can be seen in dev tools:
AFAIK, there is not a way to change that.
Instead, you can transfer the use of the margin in the button to a border.
Since you need to get space for the 1px border of the input, do the same in the button, set a 1px border (instead of a margin), and set it transparent.
The remaining trick is to set the background-clip property to padding box, so that this transparency is not affected by the background
There is another bug in Chrome, the padding expressed in em is not reliable at this level of precision when the browser is zoomed. I changed this in the snippet.
Since we are using the border button to get the dimension ok, we can style the border using instead a inset shadow.
* {
margin: 0; padding: 0; box-sizing: border-box;
}
button, input, wrapper {
display: inline-block; border-radius: 3px;
}
.wrapper {
position: relative;
width: 60%;
margin: 1em;
background-color: #ccc;
}
input {
border: 1px solid red;
width: 100%;
background-color: limegreen;
line-height: 3em;
/* padding: 0.75em; */
padding: 10px;
}
button {
position: absolute;
right: 0;
top: 0;
bottom: 0;
border: 1px solid transparent;
width: 7em;
margin: 0px;
background-clip: padding-box;
box-shadow: inset 0px 0px 0px 2px black;
}
<div class="wrapper">
<input type="text">
<button>Test</button>
</div>
Another example, where the button has a border. But we need a wrapper around it to get the dimensions ok.
* {
margin: 0; padding: 0; box-sizing: border-box;
}
button, input, wrapper {
display: inline-block; border-radius: 3px;
}
.wrapper {
position: relative;
width: 60%;
margin: 1em;
background-color: #ccc;
}
input {
border: 1px solid red;
width: 100%;
background-color: limegreen;
line-height: 3em;
/* padding: 0.75em; */
padding: 10px;
}
.buttonwrap {
position: absolute;
right: 0;
top: 0;
bottom: 0;
border: 1px solid transparent;
width: 7em;
margin: 0px;
background-clip: padding-box;
}
button {
position: absolute;
right: 0px;
top: 0;
bottom: 0;
width: 100%;
border: 2px solid blue;
margin: 0px;
}
<div class="wrapper">
<input type="text">
<div class="buttonwrap">
<button>Test</button>
</div>
</div>
Use http://autoprefixer.github.io/ to get the cross browser support you need for display: flex;
button, input, wrapper {
display: inline-block; <----- Remove "display: inline-block;"
border-radius: 3px;
}
.wrapper {
position: relative;
display: -webkit-box;<----- Add "display: flex;"
display: -webkit-flex;<----- Add "display: flex;"
display: -ms-flexbox;<----- Add "display: flex;"
display: flex;<----- Add "display: flex;"
width: 60%;
margin: 1em;
background-color: #ccc;
}
Extra reading and learning material:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
http://flexbox.io/#/
https://philipwalton.github.io/solved-by-flexbox/demos/holy-grail/
http://www.sketchingwithcss.com/samplechapter/cheatsheet.html
Note: to overide a flex rule you will need to use flex shorthand rather than specific over-ride due to current browser shortfalls eg.
.item {
flex: 0 0 300px;
}
/* overide for some reason */
.item {
flex: 1 0 300px;
}
/* NOT */
.item {
flex-grow: 1;
}
You MAY need to do an over-ride for ie11:
.ie11std .wrapper {
display:table;
}
.ie11std .item {
display:table-cell;
}
although this won't be responsive.

Control which border position sets the corner pixels in CSS

Imagine the following CSS:
#foo {
border: 1px solid black;
border-right: 1px solid blue;
}
In this case, at least under Chrome, the top and bottom right corner pixels of the element are blue, not black. Is it possible to make them black?
You can't do it with the normal CSS border options, but if you want to, you can still have a pure CSS solution:
Basically, what you are going to do is create two pseudo elements with CSS, and cover the corners:
#foo {
border: 100px solid black;
border-right: 100px solid blue;
height:300px;
position:relative;
}
#foo:after, #foo:before{
content:'';
background:black;
width:100px;
height:100px;
display:block;
position:absolute;
}
#foo:after{
bottom:-100px;
right:-100px;
}
#foo:before{
top:-100px;
right:-100px;
}
It might be a little messy, but it works. Set the :after and :before elements width height and position to the width of the border.
And that gives this effect:
JSFiddle Demo
I hope my crappy photoshop skills explain borders to you.
If you look in the 4 corners of the square you can see little lines, thats where one border starts and the next one begins.
This will always be in issue :P
You could either make it a background image (crappy way)
or you can use other divs to make the borders (crappy as well)
The first solution would be using a pseudo-element, which you will position absolutely to cover the right border. In order to ensure that it covers the border entirely, you will have to offset its top, bottom and right positions by the negative value of the border width. In this case I have used a width of 5px to better illustrate the example:
#foo {
background-color: #eee;
border: 5px solid grey;
width: 100px;
height: 100px;
position: relative;
}
#foo::before {
content: '';
position: absolute;
top: -5px;
bottom: -5px;
right: -5px; /* move by border width */
background-color: blue;
width: 5px;
}
<div id="foo"></div>
Alternatively, you can use CSS box shadow:
#foo {
background-color: #eee;
box-shadow: inset 0 0 0 5px grey;
width: 100px;
height: 100px;
position: relative;
}
#foo::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 5px;
background-color: blue;
}
<div id="foo"></div>
As others have pointed out, your problem is how borders are drawn in CSS.
<div id="foo">Problem</div>
#foo {
border: 30px solid black;
border-right: 30px solid blue;
}
The simplest way to work around this is to use a pseudo element. Since this workaround is entirely dependent on the value of the border-width, I’ll show an example using an SCSS variable to help make it clear where that width value is coming in.
Note: You don’t need SCSS to solve this problem, using a variable just helps readability/maintainability.
HTML:
<div id="foo"></div>
SCSS:
/* Set SCSS variable */
$border-width: 30px;
#foo {
border: $border-width solid black;
position: relative; /* anchor the absolute positioned ::after element */
}
#foo:after {
content: '';
background: blue;
width: $border-width;
height: 100%;
position: absolute;
right: -$border-width;
}
Demo: http://jsbin.com/cimaxe/6
Hopefully it’s clear that everywhere you see $border-width you can replace it with a value like 30px.

CSS Border with a botton

Can I achieve a custom CSS border with a button at one end which looks like this
Without url(some image link)?
Note: I want so because when I want to change color, I have to manipulate image.
I have achieved using image JS Fiddle
#stretch {
border-image: url(http://akitech.org/img/border.png) 30 30 stretch;
}
The easiest way is to use CSS pseudo-elements to create the decoration (the circle at the left) and to mask the chamfer at the right of the border (the angle at which the border-right would otherwise meet):
div {
border: 10px solid transparent;
width: 250px;
padding: 10px 20px;
position: relative;
/* this property has to be set to change the border-color: */
border-bottom-color: #f90;
}
/* common shared styles: */
div::before,
div::after {
/* to ensure the pseudo-elements are rendered: */
content: '';
/* for positioning: */
position: absolute;
/* positioning the element with its uppermost edge
against the bottom of the element, against the
upper side of the bottom-border: */
top: 100%;
/* again, set to change the color of the ends: */
background-color: #f90;
}
div::before {
/* position against the left edge: */
left: 0;
/* move the pseudo element 10px up, and
10px left: */
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
/* making the pseudo-element a circle: */
border-radius: 50%;
}
/* masking the chamfer of the border-bottom's
right-most edge: */
div::after {
left: 100%;
/* making the height/width the same width
as the border itself: */
height: 10px;
width: 10px;
}
div {
border: 10px solid transparent;
width: 250px;
padding: 10px 20px;
position: relative;
border-bottom-color: #f90;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div id="stretch">Here, the image is stretched to fill the area.</div>
In order to have these borders adapt to the length of the text, either the elements you want to have custom-bordered must themselves be able to contract to the width of the text, either using float:
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
/* forces the element to take up only that space required by
its (non-floated) contents: */
float: left;
/* forces the floated elements to the next line: */
clear: left;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
float: left;
clear: left;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
Or, possibly more simply, use display: inline-block:
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline-block;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline-block;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
Or display: inline (these don't automatically force new-lines between elements, obviously):
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
summary:
for simplist way to this question, should not using svg, pure css can draw the shape author expected very well cause it's a combination of cycle(border radius)+rect(thicker line), let's refer to the David's answer should be the easiest and most clean way to draw that shape under text.
//below is my debugging history and tries (i searched out many ways to approach it);
//though not good answers
I use background css attribute (not OP wanted) Op used border-image also valid.
<div class="custom-border" >SOME TEXT HERE</div>
<style>
.custom-border{
padding-left:20px;
width:200px;
background:url(http://img1.wikia.nocookie.net/__cb20140224040010/shantae/images/b/bc/HGH_border_bottom.png) 0px 5px no-repeat;
background-size:contain;
height:150px;
}
</style>
later I realized OP might dislike using image traditional way, I re understand the
question is asking how to draw that shape in pure css and place it under the text and the responsive should be as flexible as the traditional way the svg shape will auto strech with the text placed on it.
after that, I've find some way to generate svg and place under text
see if it works for no image solution or you can get it improved based on fiddle
http://jsfiddle.net/hahatey/hsfxS/1464/
during the process, i've found this useful tool of generating svg from below reference url: http://svg-edit.googlecode.com/svn/branches/2.6/editor/svg-editor.html
But the flaw is it's still a fixed width solution, the line svg won't auto stretch.
Have found a unclean way to improve auto stretch though not in pure css responsive way.
but auto strech can be done by dynamically change below line
<rect stroke="#ff0000" id="svg_2" height="8" width="100%" y="27" x="40" stroke-width="5" fill="#FF0000"/>
where width="100%" or fixed value => width="function return value"; //
// during this try, i found a little bug, jquery seems unable to select svg or element inside svg? however svg element tag attribute can be written in backend languge so still valid.
//3.44
Another way without touching the inner "rect' element below "svg" tag, is to add a container to the whole thing, and using function to dynamically
assign width for the container;
like my attempt in this
fiddle: http://jsfiddle.net/hahatey/hsfxS/1468/
so at least the width can be dynamically calculated out by a function to calculate the text length of the upper text so the line will be able to strech if the calculation is accurate enough. There could be other ways to do svg auto strech with the text using pure css if other ppl find it.
Thanks.
5.02// since the author didn't say how complex the content is inside the container,
I've created a demo in pure css triggered effct --- auto strech the shape along with the text above it in below fiddle. but i said it sure has many limitations though looks similar.
http://jsfiddle.net/hahatey/a9z1kyx7/
my upper fiddle is only able to align correctly for singleline auto strech
I'm wondering if complex content (more than one line, there maybe a lot of block,inline mixed tag element inside which increases complexity for alignment) can also use css to do such decoration width auto adjustment without touching javascript or backend language.

How to change content flow?

In this jsfiddle, I'm trying to create a bookmark shape. There is only one triangle which needs to change its positioning.
<div id = "bookmark">
<div id = "rectangle"></div>
<div id = "triangle-topleft"></div>
<div id = "triangle-topright"></div>
</div>
I could easily use relative positioning and shift it, but I don't want to do it this way. I want a more malleable solution.
Instead of the shapes flowing from top to bottom. I want the last shape to flow left to right. So there are 3 shapes, the first two are in the perfect place, but the third one needs to be placed to the right of the second shape, instead of underneath it.
What CSS can I use to do this?
Add float:left; to #triangle-topleft and margin-left:100px; to #triangle-topright
#triangle-topleft {
position: static;
width: 0;
height: 0;
border-top: 100px solid black;
border-right: 100px solid transparent;
float:left;
}
#triangle-topright {
position: relative;
width: 0;
height: 0;
border-top: 100px solid black;
border-left: 100px solid transparent;
margin-left:100px;
}
jsFiddle example
First of all you do not have to declare position: static; as it is already static by default (Unless you are using responsive design where you need to reset the property value at certain point of resolution), secondly, assign position: relative; to your #bookmark and make the second triangle position: absolute;
Demo
#bookmark{
width: 200px;
position: relative;
}
#rectangle {
width: 200px;
height: 300px;
background: black;
}
#triangle-topleft {
width: 0;
height: 0;
border-top: 100px solid black;
border-right: 100px solid transparent;
}
#triangle-topright {
position: absolute;
right: 0;
width: 0;
height: 0;
border-top: 100px solid black;
border-left: 100px solid transparent;
bottom: 0;
}
Note: Make sure you do not make your first triangle position: absolute; else you need to reposition the triangles. But this is the best method you can get, as you've wrapped absolute inside a relative container.
You can also take a look at this awesome thing - Font Awesome - Bookmark, you can resize this to whatever size you want to.
The thing you are trying can be also achieved by using :before and :after pseudo along with content property. So you can get rid of the extra triangle elements.
As I said, you can create this thing with a single element.
#bookmark{
width: 200px;
position: relative;
height: 300px;
background: black;
}
#bookmark:before {
width: 0;
height: 0;
border-top: 100px solid black;
border-right: 100px solid transparent;
display: block;
content: "";
position: absolute;
bottom: -100px;
}
#bookmark:after {
position: absolute;
right: 0;
width: 0;
height: 0;
border-top: 100px solid black;
border-left: 100px solid transparent;
bottom: -100px;
display: block;
content: "";
}
Here, am using :before and :after pseudo, with display: block; and content: ""; which are essential to get this thing work, also am positioning both the elements using absolute with a value set to -100
Demo (Using single element)
Note: :before and :after pseudo can fail in older versions of IE,
but you can always use polyfills to use CSS 3 properties, also, for
more information on browser support, you can check this out.
You can just add float: left to #triangle-topleft and margin-left: 100px to #triangle-topright.
To remove unnecessary markup, you could also use :before and :after pseudo-elements instead of #triangle-*.
Add display:inline-block to both triangle shapes. They're stacking because they are defaulting to display:block.
It suffices to just add float:left to #triangle-topleft and #triangle-topright.
See the fiddle: http://jsfiddle.net/nfxYE/

Scrollbar of DIV with position FIXED is partly hidden behind window scrollbar

I have a table of contents in my page (see here) with these CSS styles:
div.toc {
height:38em;
position:fixed;
right:0;
top:5em;
width:21em;
z-index:1;
}
How do I have to change these settings to make sure the DIV isn't partially hidden behind the body/window scroll bar?
(Tested with Firefox 3.6 and Opera 10.10).
Actually, your div.toc is properly positioned. The problem is with your <iframe>.
Remember your box model... width and height is calculated independently from the margin and padding...
So, by having width: 100%; on your iframe.toc plus a margin-left: 0.5em, you are basically telling the browser the following:
Use the full width of the parent element and offset it 0.5em to the left.
Total effective width: 100% + 0.5em
What you really want to say is the following:
Substract 0.5em from the full width of the parent element to use as padding on the left and use this as width.
Total effective width: 100% - 0.5em (desired)
The solution is therefore simple... Remove the margin-left from iframe.toc and put a padding-left: 0.5em on div.toc.
div.toc {
background-color: #f0f0f0;
position: fixed;
top: 5em;
right: 0;
width: 21em;
height: 38em;
padding-left: .5em;
border-left: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
z-index: 1;
}
iframe.toc {
background-color: #f0f0f0;
border: 0;
width: 100%;
height: 30em;
border-bottom: 1px solid #ccc;
}
You can make you table of contents position 1 em from the right like this: right: 1em;
I just tried it for you and right: 1em; looks good.

Resources