I think the answer to this is no but, before I make more drastic changes, I want to ensure I haven't missed something.
Is there a means, via CSS only, to alter the justification of an element and its children based on whether it's orientated more towards the left or right of the screen?
There's no straight property for this but I'm seeing if I've missed some hack-like method perhaps involving pseudo selectors or elements.
Demonstration of current predicament:
I have a <ul> nav bar that provides a mixture of <a> links and some nested <ul> containers for drop down menus on hover. Pretty standard and works fine on wider screens:
If there's less screen space available, the nav wraps to the next line as intended. This is a desirable outcome. However, sometimes the drop-down menus can be truncated off-screen, which is not very desirable:
Rather than providing a vastly different style for mobile devices (my fallback plan is to present the drop-down menus as dialog-like choices via postion: fixed on smaller screens, rather than position: absolute as they are now), I could fix my situation through my elements being aware of their adventure off-screen and the need to both text-align: right and to possibly adjust their absolute positioning to anchor to the right of the parent <li> rather than the left, as they are now:
I can manage this via javascript but I've enough listener events already occurring and want to provide a more elegant response that avoids javascript. If there's no css-only method I might use the fixed position alternative as a plan b instead.
Clarifications:
While I was originally expecting to use media queries to solve this predicament on mobile devices, I realised that, though it is only apparent on smaller screen sizes for me, this is not something I can take for granted.
For example, the number of nav items may grow in the future and could present this situation at any screen size. It just needs a drop-down menu to be at the screen right.
I also cannot guarantee that a device I've yet to test is not replicating the issue at a size I hadn't expected it to.
My point being that I don't see a way I can rely on screen size media queries. I think my solution, if any, needs to responsive to the position of the element on the screen — which is why I think I may be out-of-luck for a non-javascript solution.
Secondly: Assume content is dynamic and, like any capable page, elements that should dynamically change properties to accommodate this, do (such as nav item order, count, widths, etc.). I should refer anyone looking for finer caveats in this area to the original question: Is there a means, via CSS only, to alter the justification of an element and its children based on whether it's orientated more towards the left or right of the screen?
Sample Code:
As requested, here is the sample code. I don't think it's a good idea including it in this scenario (though understand it's importance in most questions) as it detracts from the question being mostly unrelated to my specific code and far more related to questioning the ability of css to dynamically modify an attribute(s) based on screen position or awareness of screen edges — in any scenario — hence my preference for illustrating the question.
The code is a simplified version of my own but the question could have been asked with almost any variation of a standard, familiar <ul> navigation menu that provides drop-downs via :hover in CSS.
With that in mind, if you are trying to solve the question by working through my code then I may have described my predicament poorly. I believe I'm pretty well versed in the extents that CSS can currently be pushed to and believe the answer to be 'it's not possible without javascript' but am just ensuring I haven't missed a clever workaround/hack for dynamically altering element attributes via CSS based on screen-position (sorry for repetition of the question - I just want to ensure it's understood, following some comments). Thanks.
<ul class="nav nav__container">
<li><a class='nav nav__item' href="#">Standard Link</a></li>
<li><a class='nav nav__item' href="#">Standard Link</a></li>
<li><a class='nav nav__item' href="#">Standard Link</a></li>
<li><a class='nav nav__item' href="#">Standard Link</a></li>
<li class='nav nav__item nav__item--dropdown'><li>Dropdown Label</li>
<ul class='nav nav__dropdown'>
<li><a class='nav nav__item nav__item--dditem' href="#">Dropdown Link</a></li>
<li><a class='nav nav__item nav__item--dditem' href="#">Dropdown Link</a></li>
<li><a class='nav nav__item nav__item--dditem' href="#">Dropdown Link</a></li>
</ul>
</li>
</ul>
There is indeed a CSS only solution which works exactly as you've presented in your question's attached images. However it may not be a truly complete answer as it depends on one crucial factor - that all your top level menu items have the same width. Now this is the case shown in your attached images, but may not be true of your actual implementation.
Using the CSS3 nth-child selector with the n variable you can target every 3rd, or 4th, etc top level menu item. Targeted items can easily be styled to have their dropdown menus align right. Thus, for a hard-coded solution on a single screen you would count the number of top level menu items in a row and set that as your n multiplier. For example, if your menu wrapped after 6 items, to style the last item of each row you would set something like:
.top-level-item:nth-child(6n) > .dropdown-container > .sub-item {
float: right;
clear: right;
}
or however your actual implementation needs to style a right aligned menu.
Of course, this depends on all menu items having the same width. If your menu has more than 2 rows and your menu items have varying widths then you may have a varying number of elements in each row, in which case the nth-child selector wouldn't necessarily target the end child of each row.
Now to make this work for any screen size, if all top level items have the same fixed width, we then need to find out how many items there will be per row regardless of the window's width. Sadly, calc() is too limited for this application. However, if the top items have a fixed width and we know what that width is, we can use a series of #media statements for each case.
For example, lets say that with margins and width together, each top level item has a width of 230px. This means that if the window's width is less than 230 * 3 = 690px, there will be 2 items in each row. If the window's width is less than 230 * 4 = 920px and greater than 690px there will be 3 items in each row. And so on, to the largest window size you think you'll need. Using the above nth-child example, the series of media queries to target each row size would look something like:
#media (max-width: 690px) {
/* less than 3 items per row */
.top-level-item:nth-child(2n) > .dropdown-container > .sub-item {
float: right;
clear: right;
}
}
#media (max-width: 920px) and (min-width: 691px) {
/* less than 4 items per row */
.top-level-item:nth-child(3n) > .dropdown-container > .sub-item {
float: right;
clear: right;
}
}
#media (max-width: 1150px) and (min-width: 921px) {
/* less than 5 items per row */
.top-level-item:nth-child(4n) > .dropdown-container > .sub-item {
float: right;
clear: right;
}
}
...
/* and so on */
A pen that shows an implementation of this is at https://codepen.io/jla-/pen/GYJQMq. Note that the JavaScript is only there to toggle the dropdown menus when they're clicked.
For top level menu items that have variable width, or if they have the same width but you don't know what value it is, I don't think current CSS is powerful enough to do what you want. Ideally you would do something like .top-level-item:nth-child(calc((100vw/--itemwidth)-(100vw%--itemwidth)) to get the number of items in a row, but I think CSS is a very long way off that sort of power.
May be media query with flex can help you if you use it correctly.. I tried to replicate your problem on jsfiddle.
<div id="menu-container">
<div class="menu"></div>
<div class="menu"></div>
<div class="menu">
<div id="sub-menu-container">
<div class="sub-menu" id="sub-menu1"></div>
<div class="sub-menu" id="sub-menu2"></div>
<div class="sub-menu" id="sub-menu3"></div>
<div class="sub-menu" id="sub-menu4"></div>
</div>
</div>
<div class="menu"></div>
</div>
CSS
.menu{
border-radius:15px;
background-color: #00ab9e;
width:120px;
height:50px;
border: 1px solid #01eae9;
display:inline-block;
margin:5px;
position:relative;
vertical-align:top;
}
#sub-menu-container{
margin-top:50px;
display: flex;
flex-flow: column wrap;
align-items: flex-start;
}
.sub-menu{
border-radius:15px;
background-color: #ffb12a;
width:120px;
height:50px;
border: 1px solid #01eae9;
margin-top:5px;
}
#sub-menu2{
width:150px;
}
#sub-menu3{
width:200px;
}
#media only screen and (max-width: 495px) {
#sub-menu-container {
align-items: flex-end;
}
}
#media only screen and (max-width: 420px) {
#sub-menu-container {
align-items: flex-start;
}
}
https://jsfiddle.net/nimittshah/7bsf1r3v/
Thanks
It looks like the answer to the core question:
Is there a means, via CSS only, to alter the justification of an element and its children based on whether it's orientated more towards the left or right of the screen?
is no.
As a more thorough follow-up answer I thought I'd mention that I'm not going with my original plan B of styling drop-down menus to be fixed at smaller screen sizes. I hinted at this in my question but it's become more apparent that I cannot rely on screen size to determine if a drop-down menu will be truncated in the future. So given that media queries are now ruled out, I need another solution if I want to ensure that I don't provide a sloppy solution to any device.
Which leaves me with javascript. I was trying to avoid this but, at this stage, I would be stubborn to do so given the outcome.
Method
Incase it's of use to anybody else, I used jquery to provide a listener for hovering over drop-down menus. The logic is that all elements of a certain class are guaranteed to have a drop-down menu, comprised of a <ul> of another class. So I can target both easily.
I could check if the drop-down menu is to the right or left of the screen. This would work fine. Being picky, I'd rather the menu stay justified to the left unless it's about 200 pixels from the right of the screen - a safe threshold for my dynamic content. I could go and measure each dropdown width and use that as a threshold if I ever run into issues.
Putting all of this together. If I hover over a dropdown menu and it finds itself to be less than 200 pixels from the right of the screen, it will both justify its menu to the right and absolute position the dropdown menu to the right-most side of its parent menu label/trigger (as I showed in my original illustrations). There are more flexible and shorter versions of doing this and it's also not much more work to do without jquery for anyone avoiding the library:
JS Code
$(nav).on('mouseover', '.dropdown', function() {
var dropdownlist = $(this).children('ul');
var screenWidth = $(window).width();
var parentOffsetLeft = $(this).offset().left;
var spaceRight = screenWidth - parentOffsetLeft;
if (spaceRight < 200) {
$(dropdownlist).css('text-align', 'right');
$(dropdownlist).css('right', '0');
$(dropdownlist).css('left', 'initial');
} else {
$(dropdownlist).css('text-align', 'left');
$(dropdownlist).css('left', '0');
$(dropdownlist).css('right', 'initial');
}
});
Using this javascript, I can recreate the solution illustrated in the question.
Write media-query for your requirement as you want to adjust the text justification. you can change test's justified property inside media-query. use different media-query for different display size according to your requirement, see the example
#media only screen and (max-width: 600px) {
selector {
property : value;
}
}
Related
I have two adjacent divs. One has only a single header ("MENU"). The second one is a simple table of contents. I want to show the table of contents iff user's screen width is >= 800px. In any other situation, the MENU div is hidden and table of contents is visible by default.
In order to show/hide table of contents based on screen size I use:
#media screen and (max-width: 800px) {
#tableOfContents { display: none; }
#menuSign { display: block}
I figured out how to show the table of contents when user hovers over MENU sign but I have no idea how to make it stay visible when the cursor moves from one div to the other.
#menuSign:hover + #tableOfContents {
display: block;
background: #f00;
cursor: default;
background-color: darkgray;
color: white;
}
Sorry if the answer to my question is obvious- I'm completely new to web development. All answers to similar problems either used JS (which I cannot do) or did't explain how to make table of contents persist on the screen.
If the divs have no empty space between them and the cursor can flow seamlessly from one to the other, you might try to change the selector into:
#menuSign:hover + #tableOfContents, #tableOfContents:hover { display: block; }
Also, as a personal suggestion, you should try never to use IDs in your CSS, it's bad practice: https://dev.to/claireparker/reasons-not-to-use-ids-in-css-4ni4
Moreover, if you are attempting to create a simple hamburger navigation menu, it's better to show the menu itself when the user clicks on the button instead of just hovering over it, for consistency with devices that don't have the hover functionality like mobile phones. This can be achieved in a number of different ways, the simplest involving some very simple JavaScript (or jQuery, for the simpler syntax) to add or remove a class on the DOM parent of the elements you are attempting to style now, or with hacks like using a checkbox as a proxy for the menu button.
Motive
Google receantly added a feature to display only mobile friendly pages in a mobile google search. Since I did already some CSS tricks to adopt mobile devices, I've confidently tried their test, but surprised by the results. Although I could quickly address 2 errors, there is one, that I have difficulty to quickly fix it: Links are too close together.
My site sports a menu like list, that altough I could quickly fix (and I may already have) and adopt to a mobile screen without any change in the desktop appearance, however sometimes links are inevitabely ends up above in each other in the body of each page. Also on one page there is a list that happens to have a list of links each other, but I'm not sure I would like to apply a CSS style to the list elements, to leave greater space in between list items (yet). I'm not seeking help on how to properly resolve that, (Like only leave gap between them, if they are actually end above each other) because it may fall under the "rethorical" question category. (Of course, I'm open to suggestions, if you have one.)
Question
I've decided, that I'll go with an ugly solution for now, that to leave a margin above&below each link regardless, what is surrounded with. Simply changing the margin did not worked. How can I do this? The page I'm currently testing is at http://adam.lehelj.com/ but the sub-domain is in currently only in hungarian.
Edit
The pages are generated from Markdown using PHP Extra library by Michel Fortin and I would prefer not to modify these files. It has a limited feature where to apply classes. (I believe it is for title, code and links.)
The answer as to why you cannot set a margin top or bottom to an achor can be found here, more specifically about the margin top and bottom:
These properties have no effect on non-replaced inline elements.
one solution that you could use would be to set a line-height on your anchors.
With the links on the top left of your example page you can add a class to the anchor tags.
<a class="links" href=""></a>
The css could be something like..
.links {
display: block; /* default is inline and top margin won't work on an inline element */
margin: 3px 0px 3px 0px;
}
With the social links on the page bottom top margins should work fine for you as well. Just adjust the numbers until google is happy with the spacing and sure that people with fat fingers like me aren't clicking on 5 links at a time ;)
li {
margin: 3px 0px 3px 0px;
}
If the rest of your site is more complex add a class to the ul or li or wrapper div around them to differentiate styles as needed.
html
li class="social-links-item"
css
social-links-item {
css here
}
html
<div class="social-links-wrapper">
<ul>
<li></li>
</ul>
</div>
css
.social-links-wrapper li {
css here
}
I'm creating a site with a horizontal navbar in which the buttons are designed as elements, making them easy to differentiate, and they individually light up when you a:hover over them. Here's a link: http://allpropestmanagement.net/commercial2.html
Obviously not a finished product.
My current problem involves that big purple field on the far right of the navbar, the one that's not a button. That too is an element, but with hover disabled and a whole load of nonbreaking spaces to pad it. That's the problem. I would like that purple field to extend all the way to the right end (with a tiny margin, like it does on the left side). The trouble with nbsp, as you can imagine, is that there's a finite number of them, and they don't scale. So if the navbar is the perfect length on my computer with, say, 16 nbsps, on someone else's machine it won't reach all the way and on yet another person's it will reach too far.
The html looks like this:
<div id="navmenu">
<form>
Home
Commercial
Meet The Pro
Contact
<a id="farright" style="border-top-right-radius:25px;">
<i> "We'll get the job done right!"
</i></a>
</form>
</div>
I feel odd saying this, but the css is kind of bulky and I'm having trouble formatting this post. Perhaps I'll add it in a few minutes once this post is visible, but the css file is "smithmicropurple.css".
Anyway, I would like a way to stretch that element so it always fits correctly, or if not, some other method that achieves the same effect. I have already tried setting widths individually for each element and that doesn't appear to work.
I like to do these types of things to "help" others (rarely, if I'm lucky), but also to help me learn more about html/css.
So I've given it the old college try with this FIDDLE.
HTML
<div class='holderdiv'>
<a href='#'>One</a>
<a href='#'>Two</a>
<a href='#'>Three</a>
<a href='#'>Four</a>
<a href='#'>We'll Get the Job Done Right!</a>
</div>
I won't post the CSS because it's pretty long. It's in the fiddle.
Please don't consider this a "real" answer. Perhaps just something to think about.
Semantically, I am not sure why the parent is a form element, i'd suggest changing that to a HTML5 <nav> element. (assuming you're using HTML5, of course)
The approach taken here is to set the child elements to display:table-cell, and give the targeted element, #farright a width of 100% to fill the remaining space. Also, text-align:center will effectively center all the child elements. No need for %nbsp;
#navmenu {
font-size: 14pt;
margin: 5px 0 0 5px;
}
#navmenu form {
width: 940px;
}
#navmenu form > a {
display: table-cell;
white-space: nowrap;
text-align:center;
}
#navmenu #farright {
width:100%;
}
I have the following HTML:
<ul class="baseList">
<li>
<ul class="baseListColumn">
<li>10.09</li>
<li>My title is here</li>
<li>Author</li>
</ul>
</li>
</ul>
with the following css:
.baseList {
border: 1px solid #F00;
}
.baseListColumn {
-moz-column-count:3;
-webkit-column-count:3;
column-count:3;
-moz-column-gap: 10px;
-webkit-column-gap: 10px;
column-gap: 10px;
}
My problem is, that this centers the content of every li of baseListColumn and gives every column the same width. I would like to make the columns fit it's content apart from the last li element (Author) and float the content of the last li element right.
This is what happens with the current code: http://jsfiddle.net/aLGRJ/1/
10.09 My title is here Author
asdfasdfasdfasdf My title is here abababa Author
In fiddle you can even see what happens if the width of the root li is big enough while the equal splitting of the columns is too small to contain some of the content.
This is what I would like to have:
10.09 My title is here Author
asdfasdfasdfasdf My title is here abababa Author
I can't guarantee that all the columns will always have the same length otherwise I would use absolute positioning and at the same time I don't want to reserve too much unnecessary space for the first column for example. Note I'm planning to use this for lists with more columns than just 3 as well.
Is this one of the cases where a table would be the better solution? Anyways I hope someone can help me, and if there is a better solution to this, I'm always open for suggestions.
It looks like a table would be a better solution, not because of the display properties, but because of the nature of your content (remember, organizing content is still the responsibility of HTML).
Take a look at this page.
While most of the points are generally agreeable, I tend to focus on two things:
Don’t Use Faux Tables (<p>, <div>, etc.)
Tables Should Be Filterable & Sortable (If more then just a few rows)
You can generate all of the CSS yourself... or, use your favorite ECMAScript library to make short work of styling.
On a website i'd like to show products in the following structure:
[IMAGE]
[PRODUCT TITLE]
[PRODUCT ID]
[DETAIL TEXT]
[FEATURE LIST]
[PRICE]
Resulting in a product display such as:
Now, the thing is that there are multiple products on display, just like this one, but sometimes they are aligned next to one another.
The problem is that i would like to make the price appear at the same position (vertical wise) in all blocks. Of course i see only one solution at first - overflow:hidden on the detail text / feature listing. But then i'd end up having content cut off, right?
Another problem is that there should also be a more>> button (expander) that appears if the UL/LI-listing is longer than 4 entries. Just like this:
I thought this through quite often, but i seem to find no proper solution. For one i will never know if an LI will be multiline, as the content might be longer or shorter - and i cannot calculalate this serverside, as the font width/height might vary.
I'd appreciate any constructive input here.
Thank You!
As long as you have a fixed width you could use inline-block mixed with negative margins : http://jsfiddle.net/bymaK/11/
The sad thing is that it works in Chrome, Opera and IE 9 but completely break Firefox as it's management of with:0 and negative margin seem buggy (Added issue #709014 to Bugzilla following this post). The solution is to detect this browser and set the width to 1px for it...
It create a small bug as when you resize there is 1 pixel where the price warp to the next line but not the block but it's a lot less visible that the result otherwise :
<div id="container">
<p>texttexttext</p>
<ul>
<li>texttexttext</li>
<li>texttexttext</li>
<li>texttexttext<Update/li>
<li>texttexttext</li>
<li>more »</li>
<li class="more">more text</li>
<li class="more">Even more text.</li>
</ul>
</div><p class="price">$3993.99</p>
.price
{
height:40px;
display:inline-block;
margin-left: -200px;
margin-right: 200px;
vertical-align: bottom;
font-weight: bold;
}
#container
{
display: inline-block;
margin-right:10px;
position:relative;
width:200px;
padding-bottom:40px;
vertical-align: top;
}
ul
{
list-style-type:disc;
margin-left:30px
}
li.more
{
display: none;
}
$(function(){
$('a.more').click(function(){
$(this).parent('li').hide().nextAll('li').show(200);
});
});
Maybe have the containing div set to position: relative, and then price set to position: absolute; bottom:0? That way, no matter how much text is in the box, the price is always at 0 (or whatever number you set).
Here's a rudimentary example: http://jsfiddle.net/PFwJ6/1/
You might want to use javascript to find the height and display a "click to view more link".
First, create a div over the price div that would contain your "click to see more" link and set it to display:none. Then you can use offsetHeight in javascript to find the height of the div. If the height is over what is acceptable then you would set the div to display:block. That means you can set all of your containing divs to the same height with the price div pinned to the bottom using positioning.
I'm sorry I don't have concrete code for you. I might be able to put some together shortly. But this should point you in the right direction.