Reputation: 6190
I am working on some kind of context menu. The arrow that indicates whether a row will provide a submenu should always be centered. This works well with single line <li>
elements, but not with multiline. Here the <span>
that contains the arrow symbol is aligned with the last line of the text.
It gets worse if the menu contains a scrollbar, then the arrow is beneath the line.
I am thankful for any help, the solution can contain JS/jQuery if that's required to be flexible.
You can find my current source here: http://jsfiddle.net/ass9sxo6/3/
Btw: Would be even better if the arrow symbol was in the padding area of the <li>
so that it doesn't steal any space that could be used for text.
Upvotes: 2
Views: 1244
Reputation: 982
Set .indicator
element to position: absolute;
(and give its' parent <li>
non-static positioning). Give it custom right offset (say: right: 5px;
), set .top
and .bottom
to 0, and set .line-height
to parent <li>
s' height. It centers an indicator verticaly automatically as <li>
s' height changes. Something like this should work fine:
.indicator {
margin : 0;
padding : 0;
bottom : 0;
display : block;
line-height : 50px; /* same as parents' height, assuming its' 50px... */
position : absolute;
right : 5px;
top : 0;
}
less
snippet to easily tweak menu properties. Adjust the variables in file header, export it as css, run: lessc --clean-css ul-stacked.less > ul-stacked.min.css
, and slap a ul-stacked
class to any <ul>
with this structure: FIDDLE<ul class="ul-stacked">
<li><span>ipsum</span></li>
<li class="parent"> <span> nulla <span class="indicator">></span> </span> </li>
<li><span>lorem</span></li>
<!-- etc. -->
</ul>
// ul-stacked.less
// #vars
@class-name : ul-stacked;
@class-name-feedback : indicator;
@class-name-parent : parent;
@body-bg : #f8f8f8;
@body-frame-bg : #ccc;
@body-frame-width : 2px;
@body-height-base : 50px;
@body-pad-content-base : .2em;
@border-radius-base : 2px;
@feedback-offs-right : 1em;
@spacing-bottom-base : 2px;
@body-bg-hover : lighten(@body-bg, 2%);
@body-height : @body-height-base * 1;
@spacing-bottom : @spacing-bottom-base + @body-frame-width / 2;
// #mixins
.reset-base() {
border : none;
margin : 0;
outline : none;
padding : 0;
}
.wrapper-fluid() {
display : block;
height : auto;
width : 100%;
}
.list-unstyled() {
list-style : none;
list-style-position : outside;
margin : 0;
padding : 0;
}
.borders(@r: @border-radius-base) {
border-radius: @r;
}
ul.@{class-name} {
.list-unstyled;
.reset-base;
.wrapper-fluid;
> li {
.borders;
.reset-base;
background : @body-frame-bg;
display : block;
float : none;
height : @body-height;
position : relative;
width : 100%;
> * {
&:hover {
background : @body-bg-hover;
}
background : @body-bg;
bottom : @body-frame-width;
display : block;
left : @body-frame-width;
padding : @body-pad-content-base;
position : absolute;
right : @body-frame-width;
top : @body-frame-width;
}
}
> li {
margin-bottom: @spacing-bottom;
}
> li:last-child {
margin-bottom: 0;
}
> li.@{class-name-parent} {
> * {
> .@{class-name-feedback} {
.reset-base;
bottom : 0;
display : block;
line-height : @body-height;
position : absolute;
right : @feedback-offs-right;
top : 0;
}
}
}
}
// eof
Upvotes: 1
Reputation: 2057
Instead of adding <span class="indicator"></span>
to the end of every <li>
element you can use CSS3 :after
selector with the content
attribute to append an arrow at the end of every <li>
element.
Then you set CSS attribute position:relative
on each <li>
element so that it's child elements will inherit its position. And on each li:after
content you can set display:block
and position:absolute
along with top:50%
and margin-top:-0.5em
to get the vertical alignment you want.
Here's a modification to your JSFiddle: http://jsfiddle.net/ass9sxo6/6/
And the CSS attributes I added to demonstrate the effect:
li {position:relative;}
li:after {
content: '›';
font-weight: bold;
position: absolute;
right: 5px;
top: 50%;
margin-top: -0.5em;
}
P.S. You should try use Ascii symbols where possible rather than base64 images to keep the file size small and the code easy to understand.
Upvotes: 2
Reputation: 6253
You can use absolute
:
li {
position: relative;
}
.indicator {
position: absolute;
top: 50%;
right: 0;
margin-top: -8px;
}
Upvotes: 1
Reputation: 535
Just remove the span
tag and make the background image to li
tag... Its very simple.
Check this fiddle demo.
.box li {
background-image: url(https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-arrow-right-b-16.png);
background-position:right center;
background-repeat: no-repeat;
}
<div class="box">
<ul>
<li>
This will be some multiline content
</li>
<li>
and single line
</li>
<li>
This will be some multiline content
</li>
<li>
and single line
</li>
<li>
This will be some multiline content
</li>
<li>
and single line
</li>
</ul>
<div>
Upvotes: 0
Reputation: 9615
You could center your span with this addition in your css:
.box li {
position: relative;
}
.box ul li span {
position: absolute;
top: 0;
bottom: 0;
right: 0;
margin: auto;
}
Fiddle: http://jsfiddle.net/ass9sxo6/4/
Positioned the span
element absolute with top / bottom / right values 0 and set margin to auto. In order to work needs relative position to container element li
.
Upvotes: 3