How can I make tabs with only CSS? [duplicate] - javascript

This question already has answers here:
HTML tab interface using only CSS
(3 answers)
Closed 7 years ago.
I'm looking to make a tab system like jQuery tabs, where users can between toggle different panels to view different content:
However, I need to accomplish this without the use of javascript, so that users without javascript enabled can easily use the site. Furthermore, I'd like to avoid navigating to different static html pages, each with a different style corresponding to the "tab." What's a good way to approach this?

An easy way to implement CSS-only tabs is to use radio buttons!
The key is to style labels that are attached to a respective button. The radio buttons themselves are hidden, with a little absolute positioning, off the side of the screen.
The basic html structure is:
div#holder
input[type="radio"]
div.content-holder
label
div.tab-content (all your tab content goes here)
input[type="radio"]
... keep repeating
The key is in the selectors. We are going to style the input[type="radio"] buttons with
input[type="radio"] {
position: absolute;
left: -100%;
top: -100%;
height: 0;
display: none;
}
This hoists them off the side of the screen, as mentioned above. But how do we click them then? Fortunately, if you target a label, it can click the input for you!
<label for="radioInputId1">tab title</label>
Then we style the actual labels (I'm going to leave out the aesthetic styling for brevity):
input[type="radio"] + div.content-holder > label {
display: inline-block;
float: left;
height: 35px;
width: 33%; /* or whatever width you want */
}
Now our labels should look like "tabs" at the top of the div#holder. But what about all that content? Well, we want it to all be hidden by default, so we can target it with the following selector:
input[type="radio"] + div.content-holder > div.tab-content {
display: none;
position: absolute;
top: 65px; /* this depends on your label height */
width: 100%;
}
The above CSS is the minimal CSS required to get it working. Everything other than display: none; is what you will see when the div is actually displayed. But this shows nothing in the tabs, so… now what?
input[type="radio"]:checked + div.content-holder > div.tab-content {
display: block;
}
The reason the above works is because of the :checked pseudo-class. Since the labels are attached to a specific radio button, they trigger :checked on click. This automatically turns all the other radio buttons off. Because we have have wrapped everything within a div.content-holder, we can use the next sibling CSS selector, +, to make sure we only target a specific tab. (Try using ~ and see what happens!)
Here's a fiddle, for those of you who don't like stack snippets, and here's a stack snippet, for those of you who do:
#holder {
border: solid 1px black;
display: block;
height: 500px;
position: relative;
width: 600px;
}
p {
margin: 5px 0 0 5px;
}
input[type="radio"] {
display: none;
height: 0;
left: -100%;
position: absolute;
top: -100%;
}
input[type="radio"] + div.content-holder > label {
background-color: #7BE;
border-radius: 2px;
color: #333;
display: inline-block;
float: left;
height: 35px;
margin: 5px 0 0 2px;
padding: 15px 0 0 0;
text-align: center;
width: 33%;
}
input[type="radio"] + div.content-holder > div {
display: none;
position: absolute;
text-align: center;
top: 65px;
width: 100%;
}
input[type="radio"]:checked + div.content-holder > div {
display: block;
}
input[type="radio"]:checked + div.content-holder > label {
background-color: #B1CF6F;
}
img {
left: 0;
margin: 15px auto auto auto;
position: absolute;
right: 0;
}
<div id="holder">
<input type="radio" name="tabs" value="1" id="check1" checked>
<div class="content-holder">
<label for="check1">one</label>
<div class="tab-content">
<p>All my content for the first tab goes here.</p>
</div>
</div>
<input type="radio" name="tabs" value="2" id="check2">
<div class="content-holder">
<label for="check2">two</label>
<div class="tab-content">
<h2>You can put whatever you want in your tabs!</h2>
<p>Any content, anywhere!</p>
<p>
Remember, though, they're absolutely positioned.
This means they position themselves relative to
their parent, div#holder, which is relatively positioned
</p>
</div>
</div>
<input type="radio" name="tabs" value="3" id="check3">
<div class="content-holder">
<label for="check3">three</label>
<div class="tab-content">
<p>
And maybe I want a picture of a nice cat in my third tab!
</p>
<img src="http://i.stack.imgur.com/Bgaea.jpg">
</div>
</div>
</div>
The tabs I styled are really rather basic. If you want them to "wrap" into the content, you can do that with a little extra CSS legwork.

Related

Way to remove text through CSS or JavaScript/jQuery *without* causing alignment to fail?

https://jsfiddle.net/ut1mgcLb/1/
This is my HTML:
<div class="object1">
<div class="snax-voting-container-body">
<div class="snax-voting snax-voting-positive snax-voting-large" data-snax-item-id="297">
<div class="snax-voting-score">
<strong>6203</strong> points
</div>
<span class="snax-vote-icon snax-vote-icon-caret"></span> Upvote
<span class="snax-vote-icon snax-vote-icon-caret"></span> Downvote
</div>
</div>
<a href=" https://themeforest.net/item/bimber-viral-buzz-wordpress-theme/14493994 ">
<img id="postTB" src=" https://i.imgur.com/Nf57W2G.jpg"></a> 25 Delicious Things To Cook In September (themeforest.net)<img alt="" src="//www.gravatar.com/avatar/9f221658beaba2ee853f978fa48f49c2?s=40&r=g&d=retro" srcset="//www.gravatar.com/avatar/9f221658beaba2ee853f978fa48f49c2?s=40&r=g&d=retro 2x" class="avatar avatar-40 photo" height="40" width="40">
</div>
My CSS:
#postTB{
width:10%;
}
.snax-voting-container-body {
display: inline;
align-items: center;vertical-align: middle;
position: relative;
}
.snax-voting {
display: inline-flex;
flex-direction: column;
}
.snax-voting a {
display: block;
}
.snax-voting-upvote {
order: 0;
background-image: url('https://i.imgur.com/69alhp8.png');
background-size: 10px 20px;
display: inline-block;
width: 20%;
height: auto;
content:"";
transform: translateX(50%);
}
.snax-voting-score {
order: 1;
}
.snax-voting-downvote {
order: 2;
background-image: url('https://i.imgur.com/YklTOzm.png');
background-size: 10px 20px;
display: inline-block;
width: 20%;
height: auto;
content:"";
transform: translateX(50%);
}
#postTB{
position: relative;
top: 50%;
transform: translateY(50%);
}
and my (commented out) jQuery:
//var $div = $('.snax-voting-container-body');
//$div.text($div.text().replace('points', ''))
//$div.text($div.text().replace('upvote', '^'))
Whenever I try to use that jQuery, for some reason it just causes everything to fall out of alignment.
Is there a way to remove the 'points', 'upvote', and 'downvote' text while keeping everything vertically centered?
I initially did color:transparent to hide the text before realizing how bad it looked when someone highlighted the page.
use visibility property of CSS. This will not cause alignment issues as it will take up space in the dom unlike the display property.
.hide-element {
visibility: hidden;
}
Add this class to your element and add/remove class from js on conditional values.
$div.toggleClass('hide-element', boolean_condition);
When you are retreiving the text content with $div.text(), it gets all text without the HTML tags.
Then when you are injecting it back into the div with $div.text( ... ), it sets the result as the text content of the div, actually clearing all inside of it. Because what you inject has been stripped of the HTML part, you loose your HTML tags.
try with:
$div.html($div.html().replace('points', ''))
$div.html($div.html().replace('upvote', '^'))
Howhever, take care not to replace text that belongs to your classes or tags that would correspond to "points" or "upvote" in the process.

Is there a jQuery way to make a <div> appear at the lower left of a table cell that won't destroy responsiveness?

I need to get a <div> to be at the bottom left corner of a table cell. Something like float: left; and float: bottom; together.
A typical cell is:
<td id="x0900A"> <!-- 0900 room A -->
<p class="classTitle">
</p>
<div class="classDescrip">
</div>
<p class="instructor">
</p>
<p class="gender">
</p>
<div class="instructorBio">
</div>
<div class="instructorImg">
</div>
<div id="x0900A-roomCount" class="roomCount">
<p id="x0900A-attending" class="attending">attending</p>
<p id="x0900A-capacity" class="capacity">capacity</p>
</div>
</td>
The CSS is:
td {
position: relative;
}
div[id$=roomCount] {
position: absolute;
bottom: 0;
left: 0;
width: 80px;
margin: 10px 10px 0 5px;
text-align: left;
opacity: 0.60;
}
.classTitle {
float: left;
margin: 5px 10px 10px 5px;
padding: 0 5px 0 5px;
line-height: 1.25em;
font-size: 1.05em;
text-align: left;
color: #00b8b8;
}
.instructor {
width: 50%;
float: right;
margin: 3px 0 10px 0;
padding: 0 3px 5px 3px;
line-height: 1.25em;
font-size: 0.95em;
text-align: right;
color: #00b8b8;
}
.classDescrip,
.instructorBio,
.instructorImg,
.gender {
display: none;
}
This locks .roomCount to the <td>'s bottom left but destroys responsiveness. I get horizontal overflow scrolling of the whole <body>. You can see the result here.
I tried putting a wrapper <div> inside the <td> and making it
position: relative;
height: 100%;
but it's only so tall as the wrapped content requires which, for many cells, is only partway down.
So, I need a CSS/jQuery way to anchor .roomCount that doesn't break responsiveness.
Note:
This is a resubmission of an earlier question that was too wordy and had much irrelevant content. I'm resubmitting it here in the hope that it will garner notice.
Edit/Update:
In response to #UdoE's comment: I have included the code and edited the "wordiness." At least, I hope I have and made it a better question.
In response to #ChrisG's labeling this a possible duplicate: I already noted that this is a resubmission of that question and the reason why I did it. There are no answers or comments to that question as of this writing.
If you set overflow: hidden; on the div that wraps around the element:
<div class="sqs-block code-block sqs-block-code" data-block-type="23" id="block-4f3956fa4071adb2096e">
...the horizontal scroll on the body will go away. There is already a rule affecting this element in site.css on line 13:
.sqs-block:not(.sqs-block-html):not(.sqs-block-markdown) {
clear: both;
overflow: hidden; /* add this */
}
For keeping the .roomCount element positioned in the lower left of the cell, maybe this approach can help:
.schedule td {
position: relative;
padding-bottom: 30px;
}
div[id$="roomCount"] {
margin: 0;
position: absolute;
bottom: 0;
left: 0;
max-height: 30px;
overflow: hidden;
}
What this does is place 30px of padding at the bottom of the td. Then uses absolute positioning to move the .roomCount element into the lower left corner.
This way, even though absolute positioned elements are out of flow, the padding gives you an area to work with that is going to be accounted for when the table is resizing. I added a max-height and overflow: hidden on that element just in case. It will probably take some tweaking to get right for you.
Here is a jsFiddle

Decode this Example of Dynamically Increasing Input Width

I've been doing a huge amount of reading here and on other websites about how to dynamically increase an input field's width based on its content. All the solutions so far have only worked in part, but I have found a website where it works perfectly:
https://paper.fiftythree.com/search
They've even given some vague instruction as to how they did it:
http://making.fiftythree.com/fluid-text-inputs/
But I can't for the life of me work out how to implement this on my own website.
This is my form structure at the moment:
<form action="/" class="search-form">
<input type="text" name="s" class="_input" placeholder="What are you looking for?">
<button type="submit" class="_button">Search</button>
</form>
My reason for trying to do this is that the form as a whole has a border underneath it. I would then like text that is typed in to have its own border-bottom 'grow' with the text in a different colour. The input field being a smaller width with its own border works, but I am stuck on a smooth dynamic experience for its width.
Could anyone help? Thanks.
On this example we can do this:
Input positioned absolute with fixed width this never changes, and will get the data
An element that will change the width based on the value from the input and the text transparent so that way we only see the input text.
Centered elements creating the ilusion of increase of the width
$('input').on('keypress', function() {
$('span').text($(this).val())
})
.container {
text-align: center;
position: relative;
font-size:25px;
}
.container img, .container span {
display: inline-block;
line-height: 50px;
margin-right: -4px;
vertical-align: middle;
}
.container span {
padding: 0 10px;
font-family: sans-serif;
color: transparent;
overflow: hidden;
white-space: nowrap;
max-width: 250px;
}
.container input {
width: 250px;
border: none;
text-align: center;
font-size:inherit;
padding: 0 50px;
position: absolute;
left: 50%;
top: 50%;
z-index: 5;
background: transparent;
transform: translate(-50%, -50%)
}
input:focus {
outline: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<img src="http://placekitten.com/50" alt="">
<span>Type here</span>
<input type="text" placeholder="Type here">
<img src="http://placekitten.com/50" alt="">
</div>
Note: Still have some issues when deleting text, but you get the idea

Show one element if another is above a certain height

I have a following HTML:
<span class="day-number">{{day-number}}</span>
<div class="event-box">
<div class="event-container">
</div>
<div class="more-events">more ...</div>
</div>
Event-container is filled with an unknown number of .event elements like the following:
<div class="event">{{event-name}}</div>
I want to show or hide the .more element based on if the .event-container has a height of over 76px (equal to the height of four .event elements stacked).
The styling for the above elements:
.event {
text-align: left;
font-size: .85em;
line-height: 1.3;
border-radius: 3px;
border: 1px solid #3a87ad;
background-color: #3a87ad;
font-weight: normal;
color: whitesmoke;
padding: 0 1px;
overflow: hidden;
margin-bottom: 2px;
cursor: pointer;
}
.event-box {
max-height: 76px;
overflow: hidden;
position:relative;
}
.event-box .more-events {
height: 10px;
position: absolute;
right: 0;
bottom: 10px;
display: none;
z-index: 5;
}
No styling for .event-container
I can do what I want with Javascript (jQuery):
$(".event-box").each(function(){
var $this = $(this);
if($this.children(".event-container").height() > 76){
$this.children(".more-events").css("display", "block");
} else {
$this.children(".more-events").css("display", "");
}
});
And run that every time a make a change, but I'd rather do it with CSS.
Is this possible? Maybe with pseudo elements or media queries or something?
JSFIDDLE: http://jsfiddle.net/pitaj/LjLxuhx2/
If changing the markup is acceptable there is a possibility to achieve a somewhat similarly looking page without using JavaScript to show or hide, here is the Fiddle
I have removed <div class="more-events">more ...</div> line and made elements of event class to get hide when it is necessary I also made them to appear when hovering over more ... .
The CSS I have added:
.event:nth-child(n){
display: none;
}
.event:nth-child(1),.event:nth-child(2),.event:nth-child(3),.event:nth-child(4){
display: block;
}
.event:nth-child(5){
text-indent: -9999px;
position: relative;
display: block;
color: black;
border: none;
background-color: #FFF;
}
.event:nth-child(5)::before{
position: absolute;
text-indent: 0px;
content: "more ...";
display: block;
}
.event:nth-child(5):hover{
position: static;
text-indent: 0;
border: 1px solid #3a87ad;
background-color: #3a87ad;
color: whitesmoke;
}
.event:nth-child(5):hover::before{
display:none;
}
.event:nth-child(5):hover ~ .event:nth-child(n){
display: block;
}
And for .event-box class I have commented out max-height: 76px; because in my browser 76px was not equal to the height of four .event elements stacked. Also removed update function.
I dont think it's possible using css only. but for better approach in what you are trying to do.instead of using max-height for .event-box I use this css which is add display:none to +4.event on your event container:
.event-box .event-container .event:nth-child(n+5){
display: none;
}
and now when it's more than 4 .event your more text appears. FIDDLE
UPDATE:
HERE I make little change in you js as well and make it more professional,
while you are using template to render the page, maybe you can do it as follow
<div class="event-container">
{{#each events}}
<div class="event">{{event-name}}</div>
{{/each}}
</div>
{{#if canshowmore}}
<div class="more-events">more ...</div>
{{/if}}
and
function canshowmore() {
return events.length >= 4;
}

overflow:hidden is not correctly hiding absolutely positioned elements

I'm creating a dropdown settings box, and inside it I want to be able to have dropdown submenus to group settings. The submenus should slide down, and to do so, I am using jQuery to slide down the div that contains them. However, the absolutely positioned toggles that I have appear immediately, despite the fact that they are outside the div, which is set to overflow: hidden, as can be seen in this image:
This is a sample from my html:
<div id="settings-content" class="hover-content">
<div class="setting-expandable">
Panels to display<span class="expand-button pointer">+</span>
<div class="hide expand-content">
<label class="pointer">YouTube - LinusTechTips
<input type="checkbox" class="display-none setting" data-setting="panel.yt.ltt"><span class="toggle"></span>
</label>
<br/>
<label class="pointer">YouTube - TechQuickie
<input type="checkbox" class="display-none setting" data-setting="panel.yt.tq"><span class="toggle"></span>
</label>
<br/>
<label class="pointer">YouTube - Channel Superfun
<input type="checkbox" class="display-none setting" data-setting="panel.yt.csf"><span class="toggle"></span>
</label>
<br/>
</div>
</div>
</div>
and my CSS:
.toggle {
height: 13px;
margin: 3px 0;
position: absolute;
right: 10px;
width: 27px;
}
.toggle::after {
background - color: red;
content: "";
height: 13px;
position: absolute;
right: 0;
width: 13px;
transition: 0.2s linear all;
}
.expand-content {
margin-left: 10px;
margin-top:3px;
overflow:hidden
}
.hover-content {
position: absolute;
width: 500px;
right: 15px;
background-color: inherit;
top: -15px;
border: 2px black solid;
border-radius: 14px;
padding: 5px;
display: block;
}
JS is essentially $("...").click(function(){ $("...").slideUp(); });
If I deliberately position them outside of the content area, and set overflow hidden on each thing in turn, it only hides when it affects the #settings-content container div.
I have made a fiddle for it here: http://jsfiddle.net/S4DSh/1/
I would greatly appreciate some guidance as to how I should fix this because it looks pretty weird at the moment.
Thanks in advance!
Set it's container to position:relative and overflow:hidden.
.setting-expandable {
position:relative;
overflow:hidden;
}
DEMO
You could also just add position:relative; to .expand-content but that looks like it moves the toggles a little bit.
Also see this answer it's basically the same question.
What you want to do is change the z-index for your divs.
You should put a lower z-index value on things you want to stay in the back and higher z-index values to what you want in the front. And correct me if I'm wrong but, a value of -1 would be behind the body. You can put any value like 999
#DivInTheBack{
z-index:12;
}
#DivInTheFront{
z-index:13;
}
You should take a look at the w3schools reference: http://www.w3schools.com/cssref/pr_pos_z-index.asp

Categories

Resources