Detect the current direction of the div - javascript

I have a div that it's direction is determined by the content it hosts (using dir="auto"). I would like to use CSS (if it's impossible than javascript) to determine the direction and change the absolute position of the delete span accordingly.
see here in this fiddle: https://jsfiddle.net/psjgsnby/
<div dir="auto" class="item">
text
<span>x</span>
</div>
<div dir="auto" class="item">
מימין לשמאל
<span>x</span>
</div>
css:
.item {
position: relative;
width: 200px;
}
.item span {
position: absolute;
right: 0;
top: 0;
}
i'm looking for something like this selector:
.item span:dir(rtl) {
right: auto;
left: 0;
}
but something that works cross-browser (the above works only for firefox)

Using dir="auto" gives the browser the ownership on detecting which direction to use, based on the content of the element.
Note that different browsers might give different results, based on implementation.
The dir=auto actually tells the browser to:
look at the first strongly typed character in the element and work out from that what the base direction of the element should be. If it's a Hebrew (or Arabic, etc.) character, the element will get a direction of rtl. If it's, say, a Latin character, the direction will be ltr.
In CSS you don't really have an option to check this, but if you want to use javascript you can try to do exactly the same. Find the first character that is strongly typed, and based on that use the relevant direction. The only question you got here is which languages you want to support.

I found a solution but its very far from your code. Its base on display: table because we need a dynamic direction flow for every element.
Don't forget, you can change the vertical align for different positions.
.item {
display: table;
width: 200px;
height: 50px;
}
.item .btn,
.item .content {
display: table-cell;
}
.item .btn {
vertical-align: top;
}
.item .content {
width: 100%;
vertical-align: bottom;
}
<div dir="auto" class="item">
<span class="content">text</span>
<span class="btn">
x
</span>
</div>
<div dir="auto" class="item">
<span class="content">מימין לשמאל</span>
<span class="btn">
x
</span>
</div>
Fiddle demo

If you change the display of the container to flex, this is easily achievable. You just need justify-content: space-between:
The CSS is even more compact that what you had:
.item {
position: relative;
display: flex;
width: 200px;
justify-content: space-between;
}
<div dir="auto" class="item">
text
<span>x</span>
</div>
<div dir="auto" class="item">
מימין לשמאל
<span>x</span>
</div>

Related

How can I make a general JavaScript function to toggle the visibility of a div on click?

I have a webpage with a layout of multiple divs in a gridlike arrangement that all are going to contain separate text. When clicked, I want the grid to expand into a div that is z-indexed above the other elements. on click of this div, it will close.
The thing is, I do not want to make a separate function for each one of the divs, instead I want to make a generic function that will recognize which div is being clicked, and then access the divs child paragraph element and toggle that. (There is also an img within the div).
here is a cut of the HTML with the overall format that the other sections follow.
<div id="Section" onclick="portfolio()">
<h6 class="number">2. Stand Up Jetski</h6>
<img src="../resources/images/icons8-paper-ship-100.png"
alt="Brake Disc"
id="click-image">
<p class="popuptext" id="jetski-text"> random </p>
</div>
<div id="Section" onclick="portfolio()">
<h6 class="number">3. PC build</h6>
<img src="../resources/images/icons8-workstation-100.png"
alt="Brake Disc"
id="click-image">
<p class="popuptext" id="pc-text"> random </p>
</div>
Here is the javascript I came up with from internet searches.
//Portfolio Pop ups//
function portfolio() {
parent = document.getElementById('Section');
children = parent.children[0];
children.classlist.toggle('show')
}
Here is the CSS I have for these popup texts
.popuptext {
border : 1px solid var(--black);
z-index : 100;
position : absolute;
left : 50%;
top : 50%;
margin-left : -500px;
margin-top : -50px;
height : 1000px;
width : 1000px;
visibility : hidden;
}
.popuptext .show {
visibility : visible;
}
As explained earlier, when I click the div, I want the child element to toggle visibility. So far, when I click, nothing happens.
You have an issue with some of your js and your CSS. You want to pass the clicked element into your event using this. Then use querySelector() to drill down to the popup text and toggle it. Finally in your CSS, use 100vw and 100vh to make the text fill the page, and use flex to center the text in the div.
I also just changed your ids to classes for the sections, you can only have one id of the same name per webpage.
function portfolio(el) {
const textEl = el.querySelector('.popuptext')
textEl.classList.toggle('show')
}
.popuptext {
border: 1px solid #000;
z-index: 100;
visibility: hidden;
display: flex;
height: 100vh;
width: 100vw;
margin: 0;
position: absolute;
top: 0;
left: 0;
justify-content: center;
align-items: center;
background: #fff;
}
.popuptext.show {
visibility: visible;
}
<div class="section" onclick="portfolio(this)">
<h6 class="number">2. Stand Up Jetski</h6>
<img src="../resources/images/icons8-paper-ship-100.png" alt="Brake Disc" id="click-image">
<p class="popuptext" id="jetski-text"> random 1 </p>
</div>
<div class="section" onclick="portfolio(this)">
<h6 class="number">3. PC build</h6>
<img src="../resources/images/icons8-workstation-100.png" alt="Brake Disc" id="click-image">
<p class="popuptext" id="pc-text"> random 2 </p>
</div>

Can this be achieved without js?

I have this image gallery which I want to do without the javascript. Can this be done without using the javascript ?? Just need the big picture to change when mouseover or something similar.
function myFunction(imgs) {
var expandImg = document.getElementById('expandedImg')
var imgText = document.getElementById('imgtext')
expandImg.src = imgs.src
imgText.innerHTML = imgs.alt
expandImg.parentElement.style.display = 'block'
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial;
}
/* The grid: Four equal columns that floats next to each other */
.column {
float: left;
width: 25%;
padding: 10px;
}
/* Style the images inside the grid */
.column img {
opacity: 0.8;
cursor: pointer;
}
.column img:hover {
opacity: 1;
}
/* Clear floats after the columns */
.row:after {
content: '';
display: table;
clear: both;
}
/* The expanding image container */
.container {
position: relative;
display: none;
}
/* Expanding image text */
#imgtext {
position: absolute;
bottom: 15px;
left: 15px;
color: white;
font-size: 20px;
}
/* Closable button inside the expanded image */
.closebtn {
position: absolute;
top: 10px;
right: 15px;
color: white;
font-size: 35px;
cursor: pointer;
}
<div style="text-align: center">
<h2>Tabbed Image Gallery</h2>
<p>Click on the images below:</p>
</div>
<!-- The four columns -->
<div class="row">
<div class="column">
<img src="img_nature.jpg" alt="Nature" style="width: 100%" onclick="myFunction(this);" />
</div>
<div class="column">
<img src="img_snow.jpg" alt="Snow" style="width: 100%" onclick="myFunction(this);" />
</div>
<div class="column">
<img src="img_mountains.jpg" alt="Mountains" style="width: 100%" onclick="myFunction(this);" />
</div>
<div class="column">
<img src="img_lights.jpg" alt="Lights" style="width: 100%" onclick="myFunction(this);" />
</div>
</div>
<div class="container">
<span onclick="this.parentElement.style.display='none'" class="closebtn">×</span
>
<img id="expandedImg" style="width: 100%" />
<div id="imgtext"></div>
</div>
Any help is appreciated. Sorry for adding this text as StackOverflow won't let me post this without adding more text.
Thanks in advance.
Preface
Though not impossible, I nonetheless highly recommend using JavaScript instead of CSS for this task. You should not see the following content of this answer as an alternative to JavaScript's intended purpose, but see this as a playful "solution".
Another big point to use JavaScript instead of CSS is: Using CSS for this task is not accessible at all. You should always strive to make good, easy-to-use and accessible websites.
You should especially refrain from using this in a business environment for the aforementioned reason.
CSS-only solution
Necessary HTML changes
Since CSS is cascading, the image-previews need to come before either the big image itself or its ancestor. You can imagine this like this: The HTML is a tree, and effects are only carried through down to the leaves, but cannot affect neighbouring branches as that would require backtracking at some point.
In code, this could look like this:
<!-- Either this (case 1): -->
<img class="img-preview">
<img class="big-img">
<!-- Or this (case 2): -->
<img class="img-preview">
<div>
<img class="big-img"> <!-- May be nested deeper -->
</div>
The CSS
The CSS should be relatively simple. The only issue is, that for each image-preview, a new CSS-rule needs to be added. This makes adding a new image-preview a bit more work in the future, but more importantly: It crams your CSS full with unnecessary rules! This will probably result in unused CSS-rules in case you'll rewrite some, and will hinder maintenance and readability heavily.
Friendly reminder: This should better be done by using JavaScript!
CSS' :hover-pseudo-class is effectively the same as JS' mouseover. Using this and the general sibling-combinator ~ (and potentially the descendant combinator ), we can override the big image's background-image-property depending on the image-preview that is hovered:
/* Either this (case 1): */
.img-preview:hover~.big-img {/* ... */}
/* Or this (case 2): */
.img-preview:hover~* .big-img {/* ... */}
As I have already mentioned, every image-preview requires its own CSS-rule. This is because CSS cannot use HTML-attributes for its properties (except for pseudo-elements and their content-property, I think).
This means, the CSS could look like this for the current HTML:
/* The CSS */
.img-preview[data-src="https://picsum.photos/id/10/64/64"]:hover~.big-img {
background-image: url("https://picsum.photos/id/10/64/64");
}
.img-preview[data-src="https://picsum.photos/id/1002/64/64"]:hover~.big-img {
background-image: url("https://picsum.photos/id/1002/64/64");
}
/* etc. */
/* Ignore; for styling only */
img {border: 1px solid black}
.img-preview {
width: 2rem;
height: 2rem;
}
.big-img {
width: 4rem;
height: 4rem;
}
<img class="img-preview"
src="https://picsum.photos/id/10/32/32"
data-src="https://picsum.photos/id/10/64/64">
<img class="img-preview"
src="https://picsum.photos/id/1002/32/32"
data-src="https://picsum.photos/id/1002/64/64">
<!-- etc. -->
<img class="big-img">
(Sidenote: I used attribute-selectors here, but the same thing could be done using IDs or similar, as long as every image-preview can be selected individually.)
Endnote
Adding text-descriptions while hovering may be solved in a similar fashion, but is left as a task.
Unfortunately, the big image won't stay when using this approach. If you want it to stay, you should take a look at Abd Elbeltaji's answer. They use <input>- and <label>-tags to accomplish that, together with CSS' :checked-pseudo-class.
Despite looking so, changing the HTML as shown does not restrict you in how you can style your elements, especially when using FlexBox or CSS Grid. Not only do they make styling easier, they are also meant to easily make a website responsive.
Accessibility
Again: This is not an accessible solution! This whole task should certainly be handled by JavaScript.
Should this be a public website, then I advise adding alt-descriptions for every image, even the previews. Unfortunately updating the big image's alt-attribute via CSS is impossible, making it inaccessible, which in turn harms your SEO. This being said, I commend your effort in displaying the image's alt-attribute in your original code, though not perfect. You might want to take a look at <figure>.
While we're at it: I'd also advise learning some semantic HTML-tags for the purpose of accessibility.
Pseudo-elements (::after, ::before, etc.) are also inaccessible. You should not use them to contain any relevant information/text. Though they may be used for styling-purposes in every imaginable way.
Yes, you can achieve the same behavior without the use of javascript, you may use the concept of input elements (checkbox for single toggle value, radio for multiple select values) as adjacent siblings to your elements that they should be affected of the input, and by utilizing the :checked pseudo selector for inputs in css, in a compination with the adjacent sibling selector ~ you can affect the desired elements when the input is checked. You can also use labels which will allow you to hide your inputs and trigger their values with whatever is inside your label.
// No JS!
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial;
}
/* The grid: Four equal columns that floats next to each other */
.column {
float: left;
width: 25%;
padding: 10px;
}
/* Style the images inside the grid */
.column img {
opacity: 0.8;
cursor: pointer;
}
.column img:hover {
opacity: 1;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* The expanding image container */
.container {
position: relative;
}
/* Expanding image text */
#imgtext::after {
position: absolute;
bottom: 15px;
left: 15px;
color: white;
font-size: 20px;
}
/* Closable button inside the expanded image */
.closebtn {
position: absolute;
top: 10px;
right: 15px;
color: white;
font-size: 35px;
cursor: pointer;
}
.container .img {
height: 500px;
width: 100%;
background-image: url(https://images.pexels.com/photos/15286/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
background-size: cover;
}
/* Tab select */
input[name=tabSelect],
#hideImage {
display: none;
}
#tabSelect1:checked~div.container .img {
background-image: url(https://images.pexels.com/photos/15286/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
}
#tabSelect2:checked~div.container .img {
background-image: url(https://images.pexels.com/photos/869258/pexels-photo-869258.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
}
#tabSelect3:checked~div.container .img {
background-image: url(https://images.pexels.com/photos/1183021/pexels-photo-1183021.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
}
#tabSelect4:checked~div.container .img {
background-image: url(https://images.pexels.com/photos/1124960/pexels-photo-1124960.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
}
#tabSelect1:checked~div.container #imgtext::after {
content: "Nature";
}
#tabSelect2:checked~div.container #imgtext::after {
content: "Snow";
}
#tabSelect3:checked~div.container #imgtext::after {
content: "Mountains";
}
#tabSelect4:checked~div.container #imgtext::after {
content: "Lights";
}
/* image hide btn */
#hideImage:checked~div.container {
display: none;
}
<div style="text-align:center">
<h2>Tabbed Image Gallery</h2>
<p>Click on the images below:</p>
</div>
<input type="radio" name="tabSelect" id="tabSelect1">
<input type="radio" name="tabSelect" id="tabSelect2">
<input type="radio" name="tabSelect" id="tabSelect3">
<input type="radio" name="tabSelect" id="tabSelect4">
<!-- The four columns -->
<div class="row">
<div class="column">
<label for="tabSelect1">
<img src="https://images.pexels.com/photos/15286/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Nature" style="width:100%">
</label>
</div>
<div class="column">
<label for="tabSelect2">
<img src="https://images.pexels.com/photos/869258/pexels-photo-869258.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Snow" style="width:100%">
</label>
</div>
<div class="column">
<label for="tabSelect3">
<img src="https://images.pexels.com/photos/1183021/pexels-photo-1183021.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Mountains" style="width:100%">
</label>
</div>
<div class="column">
<label for="tabSelect4">
<img src="https://images.pexels.com/photos/1124960/pexels-photo-1124960.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Lights" style="width:100%">
</label>
</div>
</div>
<input type="checkbox" id="hideImage">
<div class="container">
<label for="hideImage" class="closebtn">×</label>
<div class="img"></div>
<div id="imgtext"></div>
</div>
Here is a working example in: JSFiddle
Note! this approach is not optimal and would be tricky to expand in case you need to add more values.
PS: I had to change the images since the ones provided in your code do not exist.

How to align html?

I'm using display flex to display multiple items in one big container (parentDiv). The code is working fine but I get big problems with horizontal centering the items (especially If there are only a few items they should get horizontally centered) so I was using justify-content what leads to big issues:
The parent div is not able to display all items anymore. The first item that gets displayed is the item "04" while it should be "01". How to avoid this?
Please have a look at this code:
#bigDiv {
position: absolute;
width: 100%;
height: 100%;
}
#parentDiv {
width: 90%;
height: 50%;
overflow-y: hidden;
overflow-x: scroll;
text-align: center;
white-space: nowrap;
background: red;
display: flex;
justify-content: center;
align-items: center;
}
.item {
color: white;
background: blue;
flex: 0 0 4%;
margin: 0 3%;
}
.item::after {
content: "";
display: block;
padding-bottom: 100%;
}
<div id="bigDiv">
<div id="parentDiv">
<div class="item">01</div>
<div class="item">02</div>
<div class="item">03</div>
<div class="item">04</div>
<div class="item">05</div>
<div class="item">06</div>
<div class="item">07</div>
<div class="item">08</div>
<div class="item">09</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
<div class="item">16</div>
</div>
</div>
See this image:
My intentions: The parent div should be able to show all of the items (starting with "01" - and the last element should be the "16"-one)
Note: If there are only 4 or less items they should get centered horizontally. (The reason why I added justify-content).
You're fiting 160% into 100%. And you want it centered. And it works: the 160% total width of the resulting children is nicely centered.
But you're also expecting whatever is outside the parent to be accessible.
It's pretty much like making a child element go outside of its parent by -30% to the left or to the top (by any other method) and expecting the parent to allow you to scroll to it. It's not going to happen!
If it did, the child would no longer be placed at -30%, it would be placed at 0%. Scrollbars will never scroll to left or top negative space. It's by design. You need to take it into consideration when designing your page.
Whenever you center a bigger child into a smaller parent you won't be able to use parent's scrollbars to scroll to the beginning of the child. So anything preventing the child positioning in the parent's left negative space will fix it.

fluid div next to two fixes div's (that have changing size)

I have three div's.
the first two are fixes width,but there width should not be set to permanent size because it could change. (base of the length of text that is there)
then next to those two I have a fluid div that will change his width dynamically when the user change his window size.
how can I set this kind of structure to work? even with the use of javascript
thanks.
I don't think you can have fixed width divs that resize dynamically unless you use javascript. Have you played around with min-width and max-width css attributes?
Have a look at this demo:
for a markup like this:
<div id="contentwrapper">
<div id="contentcolumn">
...
</div>
</div>
<div id="leftcolumn">
...
</div>
<div id="rightcolumn">
...
</div>
CSS
#contentwrapper {
float: right;
width: 100%;
margin-left: -430px;
}
#contentcolumn {
margin-left: 430px;
}
#leftcolumn {
float: left;
width: 230px;
background: #C8FC98;
}
#rightcolumn {
float: left;
width: 200px;
background: #FDE95E;
}
An example: http://jsfiddle.net/sw9422oy/
IF you don't want to set a fixed width then you should use a fluid-fluid-fluid approach like this one: http://www.dynamicdrive.com/style/layouts/item/css-liquid-layout-33-fluid-fluid-fluid/

How to stack divs beside each other to create a carousel

I am trying to create a carousel, where clicking on any element will slide it leftwards, simultaneously sliding the right element into viewport. For that, I need to have the divs stacked side by side. I am trying it out as a float based layout (see Fiddle ).
Problem is that here clicking the red colored div slides it leftward alright, but not the green element leftwards. This is probably due to the fact that they are actually lying below another, as visible when the overflow: hidden is removed from #cont's style. How elese to stack them side by side so that sliding one leftward automatically slides the next one leftwards as well? (Creating the to-be-next element on the fly while clicking and animating it into viewport is a no-no, the element should be present in the DOM!)
I'd suggest you use a plugin, as there is more to this than you may realize. There are many plugins out there for this, here's a list to get you started: http://www.tripwiremagazine.com/2012/12/jquery-carousel.html
I modified your Javascript, HTML, and CSS to get you pointed in the right direction:
http://jsfiddle.net/nf5Dh/2/
You need a container contContent, positioned absolutely, and that container gets moved within the container div. You just float the elements in contContent to get them next to each other.
HTML:
<div id='cont'>
<div id="contContent">
<div id='i1'></div>
<div id='i2'></div>
<div id='i3'></div>
</div>
</div>
CSS:
#cont {
width: 50px;
padding-top: 10px;
background: blue;
height: 50px;
overflow: hidden;
position: relative;
}
#contContent {
height: 50px;
width: 150px;
position: absolute;
top: 0;
left: 0;
}
#contContent > div {
float: left;
display: inline-block;
height: 50px;
width: 50px;
}
#i1 { background: red; }
#i2 { background: green; }
#i3 { background: yellow; }
And the JS:
$("#contContent > div").click(function(){
$("#contContent").animate({left: "-=50px"},1000);
});
You'd probably be better off using an ul instead of all divs, this is at least more semantically correct, though not technically necessary.
<div id="carousel">
<ul id="carouselContent">
<li id="slide1"></li>
<li id="slide2"></li>
<li id="slide3"></li>
</ul>
</div>
This:
#cont {
white-space:nowrap;
overflow: hidden;
}
.pane { // or whatever the slide divs are called. get rid of the float.
float: none;
display: inline-block;
*zoom:1;
*display:inline;
}
You can use that carousel where you can generate javascript for the carousel http://caroufredsel.dev7studios.com/configuration-robot.php
I've used http://sorgalla.com/jcarousel/ for things like this in the past, that's based on postion: relative and left/right offsets. Probably easier than messing with floats.
You can try using a list item instead, and display them inline.

Categories