First letter not working if -webkit-box display property is set - css

I want to display the first letter in red color but I've noticed when I using display: -webkit-box the first-letter property may not works anymore.
Expected behavior :
Apply style to first-letter (in CSS only) and keep the display property which is used to active -webkit-line-clamp property (or find a CSS alternative to display the only two first lines as now without use the line-clamp and display properties which will permit to do works the first-letter property).
h2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
width: 75px;
border: 1px solid lightgray;
}
h2::first-letter {
color: red;
}
<h2>This is a pretty simple test</h2>

To be accurate, ::first-letter only works for:
display: block;
display: inline-block;
display: flow-root;
So if you want a result that fit you, you should use js Color JS based on this subject
DEMO:
(function() {
// Let's get all user names, you might have another structure
var users = document.querySelectorAll('h2');
// Create the span containing the highlighted asterisk
var asterisk = document.createElement('span');
asterisk.className = 'highlight';
// Walk the users (teehee) and check if the first characer is an asterisk
for (var i = 0; i < users.length; ++i) {
var user = users[i];
var text = user.textContent;
var firstLetter = text[0];
asterisk.appendChild(document.createTextNode(firstLetter));
user.removeChild(user.firstChild);
user.appendChild(asterisk);
user.appendChild(document.createTextNode(text.slice(1)));
}
})();
h2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
width: 75px;
border: 1px solid lightgray;
}
/*h2::first-letter {
color: red;
}*/
.highlight {
color: #f00;
}
<h2>This is a pretty simple test</h2>

Related

Shrink of inside label in a flex item

Hello everybody I need a help. The issue is the following: I have flex-container with tabs (number of tabs can be different as they are passed as array in React component).
Each tab contains label and span with a number. By initial conditions for this task, label should not be shorter than 3 letters + "..." (we apply ellipsis for it).
As I have understood, there is no other solution but to do it manually from code (ch unit is based on symbol 0, that's why this approach gives inaccurate result). But let's move to key issue. Text in label can have different length, and we can have different number of tabs.
I need to set tabs in container (let it be restricted by max-width of 900px) as long as it possible. What does it mean: we set tabs with full length of label if it is possible, if not - label shrinks until it reaches min-width (6ch). If number of tabs is too large (all labels have min-width, but tabs exceed container), I will not render them at all. I am going to implement that with help of useLayoutEffect with checks of exceeding container there.
The main problem now is that spans overflow tabs, in other words labels have possibility to shrink, but instead of that other tabs start shrinking arising problems with span. I have tried to use grid with templates columns of 1fr width (number of columns I can set by passing length of array to styled component). That works, but I need to have by tabs aligned to left side (instead of that they would take all available space) and I have problems with extra empty space if label + gap + span < 1fr of container.
By this moment I have no solution, but to hardcode min-width of tab, but all of us understand that it is unacceptable (not to mention the fact that there can be 10,000, for example, in span). I am asking for any help. I would be the happiest person if I found solution.
I have attached images with demonstration of issue, code, and link to codeSandbox with example (there you can insert tabs in mock_data, change length of words).
CodeSandBox - https://codesandbox.io/s/gracious-dijkstra-61s9sp?file=/src/Component.jsx:0-1606
tabs have enough space
labels can shrink, but instead spans overflow tabs
import styled from "#emotion/styled";
const TabsList = styled.ul`
list-style: none;
display: flex;
justify-content: flex-start;
gap: 20px;
margin: 0;
margin-left: 20px;
width: 100%;
max-width: 900px;
background: yellowgreen;
/* because the first tab always will be "all" */
li:first-of-type label {
min-width: 20px;
}
`;
const singleNumPaddingStyles = "0 8px";
const KeywordTab = styled.li`
position: relative;
overflow: hidden;
display: flex;
align-items: center;
padding-bottom: 4px;
gap: 8px;
label {
display: block;
font-weight: 400;
line-height: 23px;
cursor: pointer;
user-select: none;
text-transform: capitalize;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
color: blue;
}
/* trying to set minimum 3char + ... */
min-width: 6ch;
}
span {
color: white;
line-height: 23px;
background-color: pink;
user-select: none;
padding: ${({ singleNum }) =>
singleNum ? singleNumPaddingStyles : "0 4px"};
border-radius: 4px;
}
`;
const Group = ({ label, number }) => (
<KeywordTab singleNum={number < 10}>
<label>{label}</label>
<span>{number}</span>
</KeywordTab>
);
export const View = ({ dictionaries }) => {
//logic (useLayoutEffect)
return (
<TabsList>
{dictionaries.map(({ label, total }, index) => (
<Group key={index} label={label} number={total} />
))}
</TabsList>
);
};
//very-very-very bad desicion: hardcode min-width
// of tab ~ 88px (53px for the first - it will always be "all")
I have achieved approximately desired behaviour by using grid instead of flexbox. On parent container i've started to set number of columns dynamically and give them width of minmax(min-content, max-content) (except for the first column as there is always expected element - All). Separate tab was rewritten to grid with 2 columns - (1fr min-content respectively)
import styled from "#emotion/styled";
import { useLayoutEffect, useRef, useState, forwardRef } from "react";
export const TabsListGrid = styled.ul`
margin: 0;
width: 100%;
display: grid;
list-style: none;
background: yellowgreen;
grid-gap: 20px;
grid-template-columns: min-content repeat(${({ columns }) => columns - 1}, minmax(min-content, max-content));
max-width: 712px;
li:first-of-type label {
min-width: min-content;
}
`
const singleNumPaddingStyles = "0 8px";
const KeywordTab = styled.li`
flex-shrink: 0;
position: relative;
overflow: hidden;
display: grid;
grid-template-columns: 1fr min-content;
align-items: center;
padding-bottom: 4px;
grid-gap: 8px;
label {
font-weight: 400;
line-height: 23px;
cursor: pointer;
user-select: none;
text-transform: capitalize;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
color: blue;
}
min-width: 6ch;
}
span {
color: white;
line-height: 23px;
background-color: pink;
user-select: none;
padding: ${({ singleNum }) =>
singleNum ? singleNumPaddingStyles : "0 4px"};
border-radius: 4px;
}
`;
const Group = forwardRef(({ label, number }, ref) => (
<KeywordTab ref={ref} singleNum={number < 10}>
<label>{label}</label>
<span>{number}</span>
</KeywordTab>
));
export const View = ({ dictionaries }) => {
const [visible, setVisible] = useState(true);
const tabsRef = useRef(null);
const tabRef = useRef([]);
useLayoutEffect(() => {
if (tabsRef?.current?.getBoundingClientRect().width < 500) {
setVisible(false);
} else {
setVisible(true);
}
console.log(tabRef);
}, []);
return (
<>
{visible && (
<TabsListGrid ref={tabsRef} columns={dictionaries.length}>
{dictionaries.map(({ label, total }, index) => (
<Group
ref={(el) => (tabRef.current[index] = el)}
key={index}
label={label}
number={total}
/>
))}
</TabsListGrid>
)}
</>
);
};

How do I get a variable from a graphQl query into a pseudo element in either inline styles or styled components

I have a bit of a condrum I can't seem to solve I am querying colors from a graphQL database from DatoCMS and want to change the color of a Pseudo element in my Gatsby js app
I can do so just fine like this with a regular selector
<p style={{color: pricing.packageBorderColor.hex}} className="price-session">
<span>${pricing.priceAmount}</span> | <span>{pricing.lengthOfSession}</span>
</p>
However I am not sure how to introduce sudo selector like :after into the mix.
const ListItem = styled.li`
list-style-type: none;
font-size: 20px;
display: inline-block;
width: 330px;
&:before {
content: url(data:image/svg+xml,${encodeURIComponent(renderToString(<FontAwesomeIcon icon={faCheck} />))});
width: 20px;
display: block;
float: left;
position: absolute;
margin-left: -31px;
color: {pricing.packageBorderColor.hex} // This is what I'd ideally like to do, but doesnt seem doable
}
span{
display:block;
float:left;
margin-top:3px;
}
`
I have thought maybe styled components and This works, however I then Can't add my variables because styled components seems to live outside there scope before my loop and react component.
Updated Attempt
const CircleSave = styled.div`
&:after{
background: ({color}) => color
}
`
<CircleSave color={pricing.packageBorderColor.hex} className="circle-save">
<p>${pricing.packageSavings}</p>
<p>savings</p>
</CircleSave>
I get the following error in my rendered css
.chrVyZ:after {
background: ({color}) => color;
}
You can use styled components passed props to pass props like this:
const ListItem = styled.li`
list-style-type: none;
font-size: 20px;
display: inline-block;
width: 330px;
&:before {
content: url(data:image/svg+xml,${encodeURIComponent(renderToString(<FontAwesomeIcon icon={faCheck} />))});
width: 20px;
display: block;
float: left;
position: absolute;
margin-left: -31px;
color: ${({ color }) => color}; // This is what I'd ideally like to do, but doesnt seem doable
}
span{
display:block;
float:left;
margin-top:3px;
}
`
and then use it like normal component with a color prop:
<ListItem color={pricing.packageBorderColor.hex}/>

Referencing parent selectors using the ampersand character, and :not

The article here shows a brilliant example of using an ampersand to reference a parent selector, like so:
h3 {
font-size: 20px;
margin-bottom: 10px;
.some-parent-selector & {
font-size: 24px;
margin-bottom: 20px;
}
}
This works as expected. However, I am following BEM principles and do not wish to have overriding Sass. As you can see in my screenshot below, the styles from .js-tabby overrides the default .tabs code.
I've tried things like:
.tabs {
display: none;
visibility: hidden;
.js-tabby &:not(&) {
display: none;
visibility: hidden;
}
.js-tabby & {
display: block;
visibility: visible;
}
}
But alas, it doesn't work.
As I was writing this question, I had a thought that seemed crazy, but it worked! So, here's my first Q&A ever:
.tabs {
html:not(.js-tabby) & {
display: none;
visibility: hidden;
}
html.js-tabby & {
display: block;
visibility: visible;
}
}
The plugin I'm using attaches the .js-tabby class to the html element, so I targeted that and BOOM! It works.
This has been something that's plagued me for so long, and I hope I can save someone else further frustration.

Set DIV display:block on A:hover Trigger (using only CSS)

I'm trying to trigger a div from display:none; to display:block; when a link is hovered. I've tried to achieve the reaction through an adjacent sibling selector but the target div doesn't change from none to block. I think it's because I'm not defining the correct hierarchy, but I have no idea what else to try.
<div id="home_bar">
<div id="welcome_left">
I’m Anthony.
</div>
<div id="welcome_right">
<div id="name_desc">I love lamp.</div>
</div>
</div>
The above HTML is powered by the following CSS:
#home_bar {
display: table-row;
width: 888px;
border: 1px solid red;
margin-top: 80px;
}
#welcome_left {
letter-spacing: -1px;
font-size: 36pt;
line-height: 36pt;
width: 666px;
color: #606060;
cursor: default;
display: table-cell;
float: left;
}
#welcome_right {
float: right;
width: 200px;
display: table-cell;
position: relative;
}
#name:hover { color: #00A68D; cursor: default; }
#name_desc {
top: 50px;
position: absolute;
display: none;
}
#name:hover + #name_desc { display: block; }
I previously tried the following as the last line:
#home_bar > #name:hover + #name_desc { display: block; }
As that seemed like the right course of action based on this question, but I still can't achieve the desired affect (to be clear, the desired effect is: hover a link on the left, trigger the appearance of content on the right).
Any thoughts with regards to what I could be doing differently here? I'm hoping to avoid jQuery if I can as I'm normally a lot more comfortable working with CSS, but I'm completely stuck.
The adjacent sibling combinator has to be used with sibling elements. In this instance, #welcome_left and #welcome_right are the siblings. Therefore, when #welcome_left is hovered over, you will select the sibling #welcome_right's child element #name_desc.
EXAMPLE HERE
#welcome_left:hover + #welcome_right #name_desc {
display: block;
}
Unfortunately, you can't use the following, because #name and #welcome_right are not sibling elements. In CSS, you currently can't transverse the DOM, therefore there aren't any parent selectors.
#name:hover + #welcome_right #name_desc {
display: block; /* doesn't work because they aren't siblings .. */
}

Inverse order of elements using CSS

I'm styling a text ad and want to change the positioning of some of the text, but I don't have access to the markup so I'm trying to accomplish it with just CSS.
Right now, it displays with an h2 on one line, an anchor tag on the next, and a paragraph below that:
ad title
right-aligned ad link
ad text......................
.............................
Instead, I'd like it to display with the paragraph above the anchor:
ad title
ad text......................
.............................
left-aligned ad link
I created a jsfiddle with the markup and the current CSS. Also, it's worth mentioning that I am not supporting IE older than IE9.
Any help would be appreciated, thanks!
Sometimes you can solve this task with table-caption trick. Not everybody knows that table can have caption element which can also be moved to the bottom with caption-side property. So we can emulate it with display property:
.a-item {
display: table;
}
.a-item .site {
...
display:table-caption;
caption-side: bottom;
}
Demo: http://jsfiddle.net/Uw8BG/5/
You could also go with Flexbox, but it will not work in IE until version IE10 (old syntax). However this trick will work in IE8+.
As #Dryden Long suggests you should take a look at this answer.
I have updated your fiddle with the proper CSS.
h2 {
display: block;
font-size: 1.5em;
-webkit-margin-before: 0em;
-webkit-margin-after: 0em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
}
.a-item h2 a{
float:none;
}
.a-item p a {
float:none;
}
.a-item .site{
text-align:left;
display:block;
margin-bottom:10px;
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
box-ordinal-group: 3;
}
p {
display: block;
-webkit-margin-before: 0em;
-webkit-margin-after: 0em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
margin:10px 0 5px 0;
}
.a-item {
display: -webkit-box;
display: -moz-box;
display: box;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
box-orient: vertical;
}
.a-item p {
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
box-ordinal-group: 2;
}

Resources