Reputation: 977
I have the following HTML structure.
<div class="fieldset">
<p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
<div>
<span><i class="icon-cart"></i></span>
<input name="">
<span><i class="icon-cart"></i></span>
<i class="icon-question tooltip-top" title="Text Goes Here"></i>
</div>
</div>
I am trying to change the settings of the border-radius according to where the <input>
is positioned.
For example, if the <input>
has a <span>
just before it, its border-radius will be zero from top and bottom left.
I did this by using:
.fieldset > div > span + input {
border-radius: 0 4px 4px 0;
}
But, when there is a <span>
after the <input>
the input border radius should be zero from only the right top and bottom side. Obviously I can't use the +
selector for this one.
How can I achieve the desired results for when the <span>
is after the <input>
without using JavaScript and altering the HTML?
UPDATE:
Following the answers below and especially BoltClock♦ methods - it seems that the problem is nearly solved! The image below demonstrate all the different scenarios and the code used to apply them.
The only scenario that is not yet working, is when there is only one span before the input.
The current CSS is:
/*Fieldsets*/
.fieldset {
width: 100%;
display: table;
position: relative;
white-space: nowrap;
margin-bottom: 15px;
}
.fieldset:last-of-type {
margin-bottom: 0;
}
/*Fieldsets > Labels*/
.fieldset > p {
width: 1%;
margin-bottom: 3px;
}
/*Fieldsets > Input Container*/
.fieldset > div {
display: table-row;
position: relative;
}
.fieldset > div > * {
display: table-cell;
white-space: nowrap;
vertical-align: middle;
position: relative;
}
/*Fieldsets > Input + Icon*/
.fieldset > div > span {
border: 1px solid #B0C2CE;
padding: 5px 15px;
font-weight: bold;
width: 1%;
}
/*Fieldsets > Input + Icon Senarios*/
.fieldset > div > span:first-of-type {
border-right: 0;
border-radius: 4px 0 0 4px;
}
.fieldset > div > span:last-of-type {
border-left: 0;
border-radius: 0 4px 4px 0;
}
.fieldset > div > span:not(:only-of-type) + input {
border-radius: 0;
}
.fieldset > div > span + input,
.fieldset > div > span + textarea,
.fieldset > div > span + select,
.fieldset > div > span + .select-dropdown-single .select-dropdown-input,
.fieldset > div > span + .select-dropdown-multi .select-input {
border-radius: 0 4px 4px 0;
}
/*Fieldsets > Input + Help toolTip icon*/
.fieldset > div [class^="tooltip-"],
.fieldset > div [class*=" tooltip-"] {
text-align: center;
width: 30px;
}
The HTML:
<div class="fieldset">
<p>Normal Input</i></p>
<div>
<input name="">
</div>
</div>
<div class="fieldset">
<p>Normal Input</p>
<div>
<span><i class="icon-cart"></i></span>
<input name="">
</div>
</div>
<div class="fieldset">
<p>Normal Input</p>
<div>
<span><i class="icon-cart"></i></span>
<input name="">
<span><i class="icon-cart"></i></span>
</div>
</div>
<div class="fieldset">
<p>Normal Input</p>
<div>
<span><i class="icon-cart"></i></span>
<input name="">
<span><i class="icon-cart"></i></span>
<i class="icon-question tooltip-top" title="Text Goes Here"></i>
</div>
</div>
Upvotes: 1
Views: 414
Reputation: 723388
Normally, you cannot target an element that is a preceding sibling of another element regardless of HTML structure, because there is no previous sibling selector.
However, given your structure, there are a number of possible cases that can still be accounted for using what is currently available to you. If there will only be at most one <span>
on either side of the <input>
, or both sides, and no other <span>
elements within this <div>
element, you will be able to target the <input>
in all of these cases.
As given in the question, when there is a <span>
element appearing only before the <input>
, use an adjacent sibling selector to target the <input>
:
<div class="fieldset">
<p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
<div>
<span><i class="icon-cart"></i></span>
<input name="">
<i class="icon-question tooltip-top" title="Text Goes Here"></i>
</div>
</div>
.fieldset > div > span + input {
border-radius: 0 4px 4px 0;
}
When there is a <span>
element appearing only after the <input>
, then if that causes <input>
to be the first child of its parent <div>
, you can use :first-child
to target that <input>
only in such a situation:
<div class="fieldset">
<p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
<div>
<input name="">
<span><i class="icon-cart"></i></span>
<i class="icon-question tooltip-top" title="Text Goes Here"></i>
</div>
</div>
.fieldset > div > input:first-child {
border-radius: 4px 0 0 4px;
}
When <span>
elements appear both before and after the <input>
, you can use :not(:only-of-type)
on the first <span>
with an adjacent sibling selector to prevent matching that first <span>
in such a situation:
<div class="fieldset">
<p>Normal Input<i class="icon-question tooltip-top" title="Text Goes Here"></i></p>
<div>
<span><i class="icon-cart"></i></span>
<input name="">
<span><i class="icon-cart"></i></span>
<i class="icon-question tooltip-top" title="Text Goes Here"></i>
</div>
</div>
.fieldset > div > span:not(:only-of-type) + input {
border-radius: 0;
}
As a bonus, since you're dealing with the border-radius
property, keep in mind that you can use its longhands selectively to avoid having to deal with the third case (<span>
on both sides) altogether:
.fieldset > div > input {
border-radius: 4px;
}
.fieldset > div > span:only-of-type + input {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.fieldset > div > input:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
Notice the use of :only-of-type
in this case however, in order to prevent that selector from matching if <span>
elements are present on both sides.
Upvotes: 3
Reputation: 1771
In your special case (if your HTML does not alter alot from your given example) you could use something like this:
try removing / commenting out the first span and see the difference. It would simply apply border-radius: 0
to all input elements except for those where the previous element is a span
//EDIT
you can now see the difference directly, no commenting out necessary
.fieldset > div > input {
border-radius: 0;
}
.fieldset > div > span + input {
border-radius: 0 4px 4px 0 !important;
}
Upvotes: 0
Reputation: 3915
I can simply give the main container a class accordingly, but I want to see if there is a way to do it without the need to alter the HTML.
No, there is no selectors which select previous sibling (Is there a previous sibling selector?)
There is only a draft in the next CSS version: http://dev.w3.org/csswg/selectors-4/#general-sibling-combinators
Upvotes: 1