Tabs with only CSS (specifically, vertical Tabs) - css

I am creating my personal version of Tabs using only a CSS solution, specifically a version in which Tabs are placed aside content, in a vertical solution, so I'd need to have Tabs on the left and content on the right.
My fisrt attempt was using "Absolute positioning", to place each full content on the right side, mantaining tabs on the left. This solution runs correcly playing with opacity value of each one, as you can see in the linked example.
But... it's have a limit... Due to absolute positioning I have to "force" an height of the entire Tabs container with overflow-y:auto; rule applied to longest content. In this way, there will always be a content that will make scrollable Tabs container and not the entire page.
In an attempt to supersede these limitations, i found a possible solution using Grid layout applied to inner content, that is "animatable to auto" (please see reference here at the end of article). The specific code of the example was:
.content {
display: grid;
grid-template-rows: 0fr;
transition: 1s;
overflow: hidden;
}
.content .inside {
min-height: 0;
}
.content.expanded {
grid-template-rows: 1fr;
}
Applying it to my case, would result in this HTML:
<div class="tabs-css vertical">
<div class="tab-accordion-item">
<input id="tab-accordion_hoqc_1" type="radio" name="tab-accordion" checked="">
<label for="tab-accordion_hoqc_1"> Intestazione Tab 1 </label>
<div class="item-content">
<div class="item-content-inner">
<div class="description">
<p>...</p>
</div>
</div>
</div>
</div>
<div class="tab-accordion-item">
<input id="tab-accordion_hoqc_2" type="radio" name="tab-accordion">
<label for="tab-accordion_hoqc_2">Questa è una intestazione di prova lunga</label>
<div class="item-content">
<div class="item-content-inner">
<div class="description">
<p>...</p>
</div>
<div></div>
</div>
</div>
</div>
</div>
and this sCSS:
.tabs-css
{
display:flex;
position:relative;
height: 300px;
> .tab-accordion-item
{
$label-height:45px;
> label
{
display:block;
background: gray;
color: white;
}
> .item-content
{
overflow-y:auto;
position:absolute;
z-index:1;
top:3px;
left:0;
height:calc(100% - $label-height + 3px); // Container height - Label height + Container padding-top
width:100%;
opacity:0;
.item-content-inner {
min-height: 0;
}
}
> input[type=radio]
{
display:none;
&:checked
{
+ label
{
z-index:2;
background: red;
+ .item-content
{
opacity:1;
z-index:3;
}
}
}
}
}
&.vertical {
flex-direction: column;
> .tab-accordion-item
{
> label
{
max-width: 400px;
padding: 10px 16px;
height: auto;
line-height: inherit;
white-space: normal;
}
> .item-content {
top: 0;
bottom: 0;
left: 450px;
width: auto;
height: auto;
}
}
}
}
But, renouncing to absolute positioning I'm not able to replicate side Tabs layout.
I could add:
.tab-accordion-item {
display: flex;
}
That "seems" similar to what I'd need, placing side-by-side Tab and relative content, but the behaviour si more similar to an Accordion, instead of a Tab...

Related

A searchbox using select and input for older browsers(no flexbox)

I want to create a search box, by using a select and an input.
I have 2 issues:
I want the search input to fill all the remaining space(see the grey background);
Select and input to be connected, no space between them(because of DOM space)
Because I need to work older IE, I can't use flexbox or grid; I tried also float.
Looking for a solution where select and input width is flexible, not fixed;
I tried a trick, (in comments, width: 1%) that sometimes works, but not with select;
.searchbox {
display: table;
width: 500px;
background-color: grey;
}
select, .form-group{
display:table-cell;
margin:0;
}
/*select {
width:1%;
space:nowrap;
}*/
<div class="searchbox">
<select>
<option>Abras</option>
<option>Brat</option>
</select>
<div class="form-group">
<input placeholder="Search" name="q""/>
<span>icon_placeholder</span>
</div>
</div>
According to this float: will not work in IE9, but if you use -ms- it should work in IE10 +. I was reading around and although the website I listed said it's not supported in IE9 im finding articles of people being able to use it. Let me know if you have any issues with the following code.
img {
width: 100%;
height: 100%;
}
.wrapper {
overflow: hidden;
width: 100%;
max-width: 500px;
}
.left {
float: left;
-ms-float: left;
overflow: hidden;
}
.options {
width: 75px;
}
.search {
width: calc(100% - 110px);
}
.image {
width: 35px;
height: 35px;
}
.style {
padding: 8px;
margin: 0;
}
.full {
width: calc(100% - 25px);
}
<div class="wrapper">
<div class="left options">
<select class="left style">
<option>Abras</option>
<option>Brat</option>
</select>
</div>
<div class="left search">
<input class="style full" placeholder="Search" name="q" />
</div>
<div class="left image">
<img src="https://seeklogo.com/images/C/company-leaf-and-flames-logo-2ECEE07FDD-seeklogo.com.png" alt="img" />
</div>
</div>
Changing the display for the select to display: inline-block; aligns everything to the left.
This won't center align the fields vertically if you choose to change the height later, but I think it solves your problem.
select, .form-group {
display: inline-block;
margin: 0;
}
You can float the select and then turn the .form-group div into a block formatting context, doing this will make it respect the floats position and fill the remaining space making it dynamic. See the demo below and click here to read more about block formatting contexts
.searchbox {
display: table;
width: 500px;
background-color: grey;
}
/* select, .form-group{
display:table-cell;
margin:0;
} */
select {
float: left;
}
.form-group {
overflow: auto;
}
input {
width: 100%;
box-sizing: border-box; /* keep box model properties subtracted from width not added */
}
<div class="searchbox">
<select>
<option>Abras</option>
<option>Brat</option>
</select>
<div class="form-group">
<input placeholder="Search" name="q"/>
<span>icon_placeholder</span>
</div>
</div>
There are many ways to turn an element into a block formatting context, I have opted to set the overflow property to hidden.
If you want an element to sit on the right of .form-group make sure to add it before the .form-group element in your mark up and float it right. The form-group will then fill the remaining space in the middle of the 2 floated elements.
Lastly when using floats don't forget to clearfix your container

Two div's, first auto-adjust, second fixed width

I'm trying to make a simple subscription form, which consists of two elements:
Textbox - Floated left, fills up remaining space.
Button - Floated right, 100px width.
The problem is I can't get the textbox to fill up the remaining width.
.container
{
width: 100%;
}
.input-field
{
float: left;
}
.button
{
float: right;
width: 100px;
}
<div class='container'>
<input class='input-field'/>
<div class='button'>Subscribe</div>
</div>
http://jsfiddle.net/7nyY7/136/
For some reason the textbox is not stretching till the start of the button.
So I tried a different approach and used tables, this is exactly what I'm trying to accomplish, BUT the problem is whenever I add padding to the button and input, they both overflow each other:
http://jsfiddle.net/B46wu/111/
Is it possible to make the textbox end right where the button starts, regardless if the padding is present or not?
Because of the design, I need the textbutton and button to be exactly next to each other. Is this possible without JS? Thanks!
The best way is to use Flexbox...apply flex:1 to the input to get the remaining space
Stack Snippet
.container {
display: flex;
}
.input-field {
flex: 1;
}
.button {
width: 100px;
background: red;
color: white;
text-align: center;
}
<div class='container'>
<input class='input-field' />
<div class='button'>
Subscribe
</div>
</div>
And if you want to use float solution you will need to set the width of input is equal to calc(100% - 100px)
.container {
width: 100%;
}
.input-field {
float: left;
}
.button {
float: left;
width: 100px;
background: red;
color: white;
text-align: center;
}
input {
width: calc(100% - 100px);
box-sizing: border-box;
}
.container:after {
content: "";
display: table;
clear:both;
}
<div class='container'>
<input class='input-field' />
<div class='button'>
Subscribe
</div>
</div>
You can apply display: flex to the container, and add the flex-grow property to the textbox, which will make it grow to fill the remaining space.
You can read up on flexbox here
.container {
width: 100%;
display: flex;
}
.input-field {
background-color: red;
opacity: 0.5;
flex-grow: 1;
}
.button {
width: 100px;
background-color: blue;
opacity: 0.5;
}
<div class='container'>
<input class='input-field' />
<div class='button'>
Subscribe
</div>
</div>
For Accessibility use proper HTML as in the html below buttons instead of
<div class='button'>
Subscribe
</div>
.container{
box-sizing: border-box;
margin: 0;
padding: 0;
width: 100%;
/*This makes the immediate children into flex items*/
display: flex;
}
.input-field {
/*This will span out the whole width minus the 100px for the button*/
flex: 1;
}
button {
/*Set button width*/
width: 100px;
padding: 5px 20px
}
<div class='container'>
<input class='input-field' />
<button class='button'>Subscribe</button>
</div>

How to make flexbox child's height to fit to content instead of 100% height of its container

#container {
display:flex;
height:300px;
background:#333;
}
#child1 {
width:30%;
background:#3cf;
}
#child2 {
width:30%;
background:#3fc;
}
#child3 {
width:40%;
background:#cf3;
}
#child1_child {
width:100%;
background:#fc3;
}
pre {
margin:0px;
}
<div id="container">
<div id="child1"><div id="child1_child"><pre>CONTENT<BR>CONTENT<BR>CONTENT<BR>CONTENT</pre></div></div>
<div id="child2"></div>
<div id="child3"></div>
</div>
The height of #child1 is automatically set to the same height of #container, How can I make it to fit to #child1_child rather than 100% height of #container?
The height of #child1_child is not static, it can be changed by content inside of it, height of #child1 with static value is useless.
fit-content is limited in support; IE won't ever support it, and Firefox still requires a prefix. This solution has jQuery for demo purposes only and is not required for the solution. There are four choices:
NONE: No extra styles on .A
FIT-CONTENT: Adds the CSS property fit-content on .A
MAX-CONTENT: Adds the CSS property max-content on .A
TABLE: Adds the CSS property display:table on .A
Option 2 and 3 behave identically , so in conclusion the simplest solution is to apply display:table and it's incredibly compatible as it is simple. height: fit-content and max-content is almost as compatible with one minor caveat being that IE does not support it (IE is going the way of the dinosaur so it's pretty much a non issue).
Demo
$('.rad').on('change', switchStyle);
function switchStyle(e) {
var pick = $(this).val();
switch (pick) {
case 'nil':
$('.A').removeClass('fit max tab');
break;
case 'fit':
$('.A').addClass('fit').removeClass('max tab');
break;
case 'max':
$('.A').addClass('max').removeClass('fit tab');
break;
case 'tab':
$('.A').addClass('tab').removeClass('fit max');
break;
default:
break;
}
}
.box {
display: flex;
height: 300px;
background: #333;
}
.A {
width: 30%;
background: #3cf;
}
.B {
width: 30%;
background: #3fc;
}
.C {
width: 40%;
background: #cf3;
}
.A1 {
width: 100%;
background: #fc3;
}
pre {
margin: 0px;
}
.set {
position: relative;
z-index: 1;
bottom: 300px;
left: 30%;
width: 30ch;
font: 400 16px/1.428 Verdana;
}
.A.fit {
height: -moz-fit-content;
height: -webkit-fit-content;
height: -fit-content;
}
.A.max {
height: max-content;
}
.A.tab {
display: table;
}
<div class="box">
<div class="A">
<div class="A1"><pre>
CONTENT
CONTENT
CONTENT
CONTENT</pre>
</div>
</div>
<div class="B"></div>
<div class="C"></div>
</div>
<fieldset class='set'>
<label>NONE
<input class='rad' name='rad' type='radio' value='nil' checked>
</label>
<label>FIT-CONTENT
<input class='rad' name='rad' type='radio' value='fit'>
</label><br>
<label>MAX-CONTENT
<input class='rad' name='rad' type='radio' value='max'>
</label>
<label>TABLE
<input class='rad' name='rad' type='radio' value='tab'>
</label>
</fieldset>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Try setting min-height or min-width... Magic.
#container {
display: flex;
height: 100%;
min-height: 0;
}
By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property. (See §4.5 Automatic Minimum Size of Flex Items.)
https://www.w3.org/TR/css-flexbox-1/#propdef-flex
Using of experimental values of the height CSS property is generally discouraged.
If it is individual flexbox child which you want to fill the height according to its content, use align-self: baseline; for it (see the example). If it is all the children, put align-items: baseline; into the parent container.
#container {
display: flex;
height: 300px;
background: #333;
}
#child1 {
width: 30%;
background: #3cf;
align-self: baseline;
}
#child2 {
width: 30%;
background: #3fc;
}
#child3 {
width: 40%;
background: #cf3;
}
#child1_child {
width: 100%;
background: #fc3;
}
pre {
margin: 0;
}
<div id="container">
<div id="child1"><div id="child1_child"><pre>CONTENT<BR>CONTENT<BR>CONTENT<BR>CONTENT</pre></div></div>
<div id="child2"></div>
<div id="child3"></div>
</div>

Centering the middle of three divs and positioning the other two relative to the middle one

Sorry if the title is confusing. Basically, I'm working on a tumblr theme where I need three adjacent divs wrapped in a fixed-width container. None of their contents are fixed, so they all have variable widths. The middle div should always be centered to the container, while the divs to the left and right will always be "touching" the middle div, and, thus, move around as the middle div's width changes (the left and right s may be images, so text-align doesn't always work). Plus, I may also need to hide the left, right, or both the left and right divs.
Here's a conceptual image:
I can obtain this using flexboxes easily (JFiddle), but flex only has 86% global support.
This is the closest I could get without using flexboxes, but I can't get that middle div (with the text) centered to the title div, while preserving the relative positions of the two images on either side: JFiddle
* {
height: 100%;
position: relative;
}
body {
height: 200px;
}
/* just to get rid of scrollbar */
p {
margin: 0;
}
.title {
background: #aaa;
height: 22px;
width: 450px;
/* for example */
margin: 0 auto;
}
.container {
background: #abc;
float: left;
}
.lr {
transform: translate(0, -100%);
}
.left {
background: green;
float: left;
}
.left img {
transform: translate(-100%);
}
.center {
background: red;
display: inline-block;
z-index: 2;
}
.right {
background: blue;
float: right;
}
.right img {
transform: translate(100%);
}
.left img, .right img {
height: 100%;
}
<div class="title">
<div class="container">
<div class="center">CENTERCENTERCENTERCEN</div>
<div class="lr">
<div class="left">
<img src="http://i.imgur.com/7bvErJN.jpg" />
</div>
<div class="right">
<img src="http://i.imgur.com/q8Mq0YZ.jpg" />
</div>
</div>
</div>
</div>
Other people have mentioned trying to display the title as a table, but that would require centering the middle cell to the whole row, and having the cells to the left and right take up the rest of the space, and I'm not sure if you can do that when their widths aren't fixed.
Anyone know of any other solutions?
If you can change your HTML then apply this:
First move the left and right elements inside center:
<div class="center">
CENTERCENTERCENTERCEN
<div class="left">
testtest<img src="http://i.imgur.com/7bvErJN.jpg" />
</div>
<div class="right">
<img src="http://i.imgur.com/q8Mq0YZ.jpg" />
</div>
</div>
Then on the CSS :
/*Keep the center container on the middle*/
.title {
text-align:center;
}
.center {
position:relative;
display:inline-block;
}
/*Position elements based on the relative center parent*/
.left {
position:absolute;
top:0;left:0;
transform:translateX(-100%)
}
.right {
position:absolute;
top:0;right:0;
transform:translateX(100%)
}
Check this DemoFiddle
Using position: absolute should help in this.
I changed your HTML to following:
<div class="title">
<div class="container">
<img class="left" src="http://i.imgur.com/7bvErJN.jpg" />
<div class="center">CENTERCENTERCENTERCEN</div>
<img class="right" src="http://i.imgur.com/q8Mq0YZ.jpg" />
</div>
</div>
CSS
.title {
background: #aaa;
height: 22px;
width: 450px;
/* for example */
margin: 0 auto;
text-align: center;
}
.container {
background: #abc;
display: inline-block;
margin: 0 auto;
position: relative;
text-align: left;
}
.center {
background: red;
}
.left, .right {
position: absolute;
top: 0px;
}
.left {
right: 100%;
}
.right {
left: 100%;
}
Working Fiddle
Updated to show OP Update
No need for flex here, why not just use percentages? Float all the containers and put the percentages as relative to the sizes you want. (50% for the middle, 25% for the outside containers).
You can use the outside containers as wrappers so you can still use a border on the inner containers without messing up the sizing. Then just float the inner containers within the outside containers (if that makes sense). The example below just floats the inner p tags to the outer containers.
This makes it always hug the inner container, while keeping relative sizes and also keeping the middle centered.
Example below:
Fiddle
HTML
<div class="container">
<div class="flexa">
<div class="left">
<p>leftleft</p>
</div>
<div class="center"><p>CENTERCENTdsfdfdERCENTsdfdfsfERCEN</p></div>
<div class="right">
<p>ri</p>
</div>
</div>
<div class="bottom">BOTTOMOMOM</div>
</div>
CSS
* {
margin: 0;
padding: 0;
}
div {
background: #aaaaaa;
overflow: hidden;
}
p{
border: 1px solid black;
}
.container {
width: 500px;
/* for example */
margin: 0 auto;
}
.right p{ /* This is what makes it work. This could be a div with class of inner or something like that. */
float:left;
}
.left p{
float:right;
}
.flexa div{
float:left;
}
.left {
width:25%;
}
.center {
width: 50%;
}
.right {
width:25%;
}
.bottom {
display: block;
margin: 0 auto;
text-align: center;
}

How to make div to expand vertically without using overflow or javascript or hardcoded values such as margins

This plunkr shows the issue.
http://plnkr.co/edit/Zr4ncVcNa53Sawbk42kK?p=preview
I'd like the blue divs to precisely cover up the red divs.
How do I do this?
The yellow divs cannot be hardcoded in terms of height because their content is variable.
I can't use overflow else the SVG will also overflow, cutting off my chart.
If restructuring the HTML is required (add, remove or moving elements), I can't do it at or above the container class (as I use an HTML partial system and this HTML is generated via nested partials).
I'd like it purely done in the container, variable and fill-vertically CSS classes.
HTML
<li class="fixed left">
<view-widget>
<view-gadget>
<div class="container">
<div class="variable">
Title
<br>
Subtitle
<br>
Something else
</div>
<div class="fill-vertically">
SVG Kendo Chart
</div>
</div>
</view-gadget>
</view-widget>
</li>
<li class="fixed right">
<view-widget>
<view-gadget>
<div class="container">
<div class="variable">
Title
</div>
<div class="fill-vertically">
SVG Kendo Chart
</div>
</div>
</view-gadget>
</view-widget>
</li>
CSS
.container {
background:green;
}
.variable {
background: yellow;
}
.fill-vertically {
background: blue;
color: white;
}
.fixed {
background: red;
list-style: none;
height: 150px;
width: 45%;
}
.left {
position: absolute;
left: 0;
}
.right {
position: absolute;
right: 0;
}
Using flexible boxes: Plunker
.container {
height: 100%; /* fill .fixed's height */
display: flex;
flex-direction: column;
}
.fill-vertically {
flex-grow: 1;
}
Compatibility: Chrome, Firefox 28+, IE11+.
Use the display:table trick in case you need to support older browsers: Plunker
.container {
display: table;
width: 100%;
height: 100%; /* fill .fixed's height */
}
.variable, .fill-vertically {
display: table-row;
}
.variable {
height: 1px; /*computed = as little height as possible to fit content*/
}
.fill-vertically {
height: 100%; /*computed = remaining available height*/
}
Compatible with IE8+ and all modern browsers.

Resources