What is the idiomatic way to position an element (X) to the left of an other element (inline-box 2), independent of its size, using standard CSS & HTML?
It is okay if it appears over other elements.
I have found a solution: to position an element to the left of another one, no matter their sizes, make it its child, and then absolute-position it right: 100%.
100% means the width of its parent, so 100% from the right will put it just left of it!
Using left: -100% wouldn't work, because it means: offset the left of the element left of the parent by the parent's width, however we want to offset by the width of the child element, itself.
CSS-only demo:
/* The important parts */
#box2 {
position: relative;
}
#x {
position: absolute;
right: calc(100% + 5px);
top: -1px;
}
/* Just styling */
#box1, #box2 {
border: 1px solid blue;
width: 200px;
margin-right: 10px;
display: inline-block;
}
#x {
border: 1px solid orangered;
width: 100px;
height: 150px;
}
<div id="container">
<div id="box1">box1</div>
<div id="box2">box2
<div id="x">X</div>
</div>
</div>
Related
I'd like to set a margin all around a <div> with a position:absolute inside a scrollable <div> to let some free space between the inside div and the scrollable area boundaries (right and bottom).
I tried something like this but with no luck:
<div style="overflow:scroll">
<div style="position:absolute; margin-right:100px; margin-bottom:100px">DRAG ME</div>
</div>
Demo here: https://jsfiddle.net/ayft01x0/
Only the margin-bottom works, and only in Chrome.
You can also imagine that there are other elements inside the scollable div and that they should stay clickable even if they are masked by the margin of the "drag me" element (which should be the case when using CSS margins).
I'm looking preferably for a CSS-only solution that works in Webkit browsers.
Any ideas?
Absolute positioning changes the way margins work, but you can get the effect you're after with borders:
We add a border to the left and the right. This interferes with the border you already had on the draggable element, so we add a pseudoelement to take care of the design. The pseudoelement covers up the "drag me" text, so we add a wrapper around that content and fix the z indices
Here's an update to your fiddle, and here's a snippet of the essential css
#container {
position: relative;
width: 200px;
height: 200px;
border: solid 1px black;
background-color: white;
}
#box {
position: absolute;
border-right: 100px solid transparent; /* changed this */
border-bottom: 100px solid transparent; /* changed this */
outline: 1px solid red; /* just for demo purposes */
width: 80px;
height: 80px;
left: 50px;
top: 50px;
/* dropped the border and background styles */
}
#box span { /* added this element */
position: relative;
z-index: 1;
}
#box:before { /* added this element */
content: '';
position: absolute;
z-index: 0;
width: 80px;
height: 80px;
/* placement adjusted to take the border into account */
left: -2px;
top: -2px;
/* border and background styles moved from #box to here */
border: solid 2px #666;
border-radius: 10px;
background: #ccc; /* shaved off a couple bytes by dropping the -color */
}
<div id="container" style="overflow:scroll">
<div id="box">
<span>DRAG ME</span><!-- added this wrapping element so that it can get a z-index -->
</div>
</div>
Note that I've kept your initial positions for the draggable box, but I would probably actually do it like this. The negative margins are just half the element's dimensions. This way if you tweak the size of #container you don't have to recalculate #box's starting position
#box {
...
width: 80px;
height: 80px;
left: 50%;
top: 50%;
margin-left: -40px;
margin-top: -40px;
}
There is a workaround by using an encapsulating div with inner padding and make it transparent to the mouse interactions using the pointer-events property.
<div style="overflow:scroll">
<div style="position:absolute; padding-right:100px; padding-bottom:100px; pointer-events:none">
<div style="pointer-events:all">DRAG ME</div>
</div>
</div>
Demo here: https://jsfiddle.net/1axtonez/
The easiest way to achieve this is to create an invisible CSS ::before pseudo-element that covers the box plus a padding, and to make it transparent to the mouse interactions using the pointer-events property:
div.box::before{
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding-right: 100px;
padding-bottom: 100px;
pointer-events: none;
/* background-color: rgba(255,0,0,0.2); // to understand what is going on */
}
Demo here: https://jsfiddle.net/rmxwwyno/
Be warned that it's not working when the box has an overflow property that is not set to visible.
Is there something about CSS that doesn't allow you to specify both top and bottom or left and right values?
Take this example:
div {
width: 100px;
height: 100px;
}
.first {
background-color: blue;
position: relative;
left: 100px;
right: 50px;
}
.second {
background-color: yellow;
}
<div class="first"></div>
<div class="second"></div>
Try removing right: 50px and the position will remain the same. What's going on?
In your example, the element has a fixed width to 100px and you are specifying both left and right properties. On MDN, you can read (emphasis mine) :
When both the right CSS property and the left CSS property are
defined, the position of the element is overspecified. In that case,
the left value has precedence when the container is left-to-right
(that is that the right computed value is set to -left)[...]
So in your example the right value is ignored. For the bottom property, the same rule applies as the element's height is fixed.
Note that this rule only applies for non static positioning
You can combine left/right and top/bottom, but if width/height is also present, their value take precedence, which makes some sense, as how can it be both at a certain right/bottom position and have a certain width/height.
This sample shows how it behaves.
body {
margin: 0;
}
.first, .second {
width: 50px;
height: 50px;
}
.first {
background-color: yellow;
}
.second {
background-color: blue;
position: absolute;
left: 50px;
right: 50px;
top: 50px;
bottom: 50px;
}
.third {
background-color: green;
position: absolute;
left: 100px;
right: 100px;
top: 100px;
bottom: 50px;
}
<div class="first"></div>
<div class="second"></div>
<div class="third"></div>
From MDN:
When both the right CSS property and the left CSS property are
defined, the position of the element is overspecified. In that case,
the left value has precedence when the container is left-to-right
(that is that the right computed value is set to -left), and the right
value has precedence when the container is right-to-left (that is that
the left computed value is set to -right).
Here's part of a design:
As you can see - its simply a button that is exactly positioned between the two divs. The code is simply:
<div class="uc-apply-widget1">
<div class="top">
</div>
<div class="bottom">
<a>Get Started</a>
</div>
</div>
.uc-apply-widget1
{
.top
{
background-color:#primary-color;
height:30rem;
}
.bottom
{
background-color:#primary-600;
padding:0 1.6rem 1.6rem 1.6rem;
a
{
margin-top:-2.8rem;
}
}
}
However, I've come across a problem with using negative margins. I expected to just be able to move the button outside of the bottom div by applying a half height negative margin. Although the button does move upwards, it doesn't move the full 2.8 rem - the amount of movement is the same even if I apply 50rem.
The other solution is to use position relative, which does move the button up, but does not drag the bottom div upwards with it.
So I'm looking to move the button up by n amount and reduce the bottom div height by n amount - any ideas - I may just be having a bad day.
use
position: absolute;
top: 0; left: 0;
transform: translateY(-50%);
on your button
https://developer.mozilla.org/en-US/docs/Web/CSS/transform
Here is one way of realizing your design.
Set the a element to have display: table and position: absolute with
top and left offsets to 0 and 50% respectively.
The display: table rule will give you a shrink-to-fit width, which may be what you need.
You can then use the CSS3 transform property to translate the element by -50% both in the X and the Y directions to get the centering.
The advantage here is that you don't have to specify the dimensions for the a element.
.uc-apply-widget1 {
width: 400px;
margin: 0 auto;
}
.top {
background-color: beige;
height: 10rem;
}
.bottom {
background-color: lightgray;
height: 5rem;
padding: 0 1.6rem 1.6rem 1.6rem;
position: relative;
}
a {
display: table;
width: auto;
margin: 0 auto;
padding: 10px;
border: 1px dotted blue;
position: absolute;
top: 0;
left: 50%;
transform: translateY(-50%) translateX(-50%);
}
<div class="uc-apply-widget1">
<div class="top">
</div>
<div class="bottom">
<a>Get Started</a>
</div>
</div>
I'm working with this JS Fiddle: http://jsfiddle.net/BY3tz/1/
Notice when you remove the position, left, and top properties from the dotParent CSS class, the black dot is centered within the box.
I'm looking for a way to keep the black dot centered (vertically and horizontally) while leaving the 3 properties mentioned above in place so that I can change the left and top properties to position the box anywhere, and the black dot will remain centered.
Is this possible? Can anyone see what I'm doing wrong with my dot class?
Some tweaks to the .dot class:
.dot {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50px;
margin-left: -5px; // Half of the width * (-1)
margin-top: -5px; // Half of the height * (-1)
top: 50%;
left: 50%;
background: #000;
-webkit-border-radius: 50px;
-webkit-background-clip: padding-box;
background-clip: padding-box;
}
http://jsfiddle.net/BY3tz/2/
Added dot wrapper so .dot is relative to new wrapper,
<div class="dotParent">
<div class="dot-wrapper">
<div class="dot"></div>
</div><!-- end dot-wrapper -->
</div>
New Styles.
.dot-wrapper {
position:relative;
width:100%;
height:100%;
}
Added to .dot class
.dot {
position:absolute;
top:45%;
left:45%;
}
http://jsfiddle.net/BY3tz/5/
Change the position attribute in the dotParent div to "Relative". Since its the parent Div, it needs to be positioned as Relative in order for its children to take it as a reference point.
.dotParent {
position: relative;
top: 150px;
left: 50px;
height: 68px;
width: 68px;
border: 1px solid Black;
}
http://jsfiddle.net/BY3tz/6/
anybody knows why this code doesnt work:
#interieur{
display: inline-block;
position: absolute;
left:50%;
}
and this one does
#interieur{
display: inline-block;
position: absolute;
left:500px;
}
I'm working in PHP and the div "interieur" is inside an echo
It doesn't work because you have forgotten to subtract half of your div width to the left position (think about it, if left would be 50% and right 50% too, your div would be 0% wide :)
You can use CSS3 Calc to achieve the result, knowing before the dimensions of your div:
#interieur{
display: inline-block;
position: absolute;
left:calc(50% - 100px); /* 100px is half of your div width */
border: 1px solid #ccc;
width: 200px;
height: 200px;
}
Demo: http://jsfiddle.net/zZHRY/3/
If you can specify a width of your div, try this:
width: 500px; /* insert width here */
margin: 0 auto;