How to repeat an item multiple times in HTML or CSS? - html

I need to place a star, ★, on a Web page, repeatedly. Is there a way to specify a symbol and how many times it should appear, in HTML or CSS? E.g., something like this, but not necessarily the same syntax, in which an item is specified, along with a quantity:
<repeat n="5">★</repeat>
This will result in:
★★★★★

You could place the star as a repeating background image of an element; and tweak the width of the element via CSS. Something like:
.stars {
display: inline-block;
width: 13px;
height: 13px;
background-image: url(https://i.stack.imgur.com/KaEDC.png);
}
.stars-2 {
width: 26px;
}
.stars-3 {
width: 39px;
}
.stars-4 {
width: 52px;
}
.stars-5 {
width: 65px;
}
<span class="stars"></span><br>
<span class="stars stars-2"></span><br>
<span class="stars stars-3"></span><br>
<span class="stars stars-4"></span><br>
<span class="stars stars-5"></span>

Use content property like this:
Note: that using repeat is not recommended in your case its not a valid html tag, use div, span or a.
Demo
Use SCSS or LESS to generate style sheet like this.
CSS:
<style>
repeat {
display:block;
}
repeat[n="1"]:before {
content: "★";
}
repeat[n="2"]:before {
content: "★★";
}
repeat[n="3"]:before {
content: "★★★";
}
repeat[n="4"]:before {
content: "★★★★";
}
repeat[n="5"]:before {
content: "★★★★★";
}
</style>
HTML:
<repeat n="1"></repeat>
<repeat n="2"></repeat>
<repeat n="5"></repeat>

If you are willing to use jQuery (or just javascript but different code), you could do:
$(document).ready(function() {
$('[repeat]').each(function() {
var toRepeat = $(this).text();
var times = parseInt($(this).attr('repeat'));
var repeated = Array(times+1).join(toRepeat);
$(this).text(repeated).removeAttr('repeat');
});
});
Then when you have
<span repeat="5">★</span>
It will become
<span>★★★★★</span>

Try:
body{
counter-reset: Counter;
}
sameTypeElement::after{
counter-increment: Counter;
content:counter(Counter) " ★";
}
or simpler:
sameTypeElement::after{
content:'★';
}
sameTypeElement siblinging is unknown for different browsers, but must work with any level of nesting tiying to type of selector

If you just want to print the star a certain number of times you can use JavaScript:
for (var i = 0; i < 5; i++) {
document.write("&#9733");
}
Will result in: ★★★★★
If you want to be able to access a particular star, you will need to wrap each star in a span and give it a unique id:
for (var i = 0; i < 6; i++) {
document.write("<span id=\"star" + i + "\">&#9733</span>");
}
This will result in:
<span class="star0">★</span>
<span class="star1">★</span>
<span class="star2">★</span>
<span class="star3">★</span>
<span class="star4">★</span>

Related

how to justify text in multiple links vertically

I need all the links below to be justified vertically, i.e. on left and right side.
font-size should be as is.
Obviously the only way is to adjust letter-spacing, but is it possible to do this automatically for all links inside .wrap.
a{display:block; text-decoration:none;}
.a1{font-size:0.7rem;}
.a2{font-size:1rem;}
.a3{font-size:1rem;}
.a4{font-size:0.7rem;}
<div class='wrap'>
<a href='index.php' class='a1'>LOREM IPSUM</a>
<a href='index.php' class='a2'>DOLOR SIT</a>
<a href='index.php' class='a3'>BLUE SKY</a>
<a href='index.php' class='a4'>DEEP OCEAN</a>
</div>
This is what I came up with. A bit "dirty" but it does exactly what you want. You may find ways to inprove the code as mine runs the same loop twice but I wrote this quickly. At least you'll get an idea.
First, set the display of a tags to inline-block to be able to measure the largest width of all. Once you have that maxWidth, loop through all elements, wrap each character in a span, and set the display of a tags to flex.
CSS:
a{
display: inline-block;
width: auto;
justify-content: space-between;
text-decoration:none;
clear: both;
}
a.flex{
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.a1{font-size:0.7rem;}
.a2{font-size:1rem;}
.a3{font-size:1rem;}
.a4{font-size:0.7rem;}
a span{
display:inline-block;
}
JS:
var elements = document.querySelectorAll(".wrap > a");
var maxWidth = 0;
for (var i = elements.length - 1; i >= 0; i--) {
maxWidth = Math.max(maxWidth, elements[i].offsetWidth);
}
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].classList.add("flex");
elements[i].style.width = maxWidth+ "px";
var text = elements[i].textContent;
text.split("");
elements[i].innerHTML = "";
for (var j = 0; j < text.length; j++) {
var span = document.createElement("span");
// Fix: issue reported by Chris L
// Replace space with non-breaking space HTML code
span.innerHTML = (text[j] === " ")? " " : text[j];
elements[i].appendChild(span);
}
}
Working example here: https://jsfiddle.net/nLdx923c/
One way to come at least close to what you want: use text-align-last: justify, a letter-spacing value in em (i.e. relative to the font-size) and a fixed width on the wrapper element, finding appropriate values by trial & error:
.wrap {
width: 95px;
}
a {
display: block;
text-decoration: none;
}
.a1 {
font-size: 0.7rem;
}
.a2 {
font-size: 1rem;
}
.a3 {
font-size: 1rem;
}
.a4 {
font-size: 0.7rem;
}
a {
text-align-last: justify;
letter-spacing: 0.08em;
}
<div class='wrap'>
<a href='index.php' class='a1'>LOREM IPSUM</a>
<a href='index.php' class='a2'>DOLOR SIT</a>
<a href='index.php' class='a3'>BLUE SKY</a>
<a href='index.php' class='a4'>DEEP OCEAN</a>
</div>

CSS - Have Image Move With Centered Text-Align Input Text

I have an text input with the following HTML:
<span>
✍
</span>
<input type="text">
and the corresponding CSS:
input{
text-align: center;
border: none;
outline: none;
background-color: transparent;
}
The input element should blend seamlessly into its background with only the HTML icon indicating that it is indeed an input. The HTML icon will remain in a static position with the current mark-up as new text is added into the input.
Is there anyway to have my HTML icon start right to the left of the first letter and have it gradually move toward the left as the left boundary of the text string pushes in the same direction?
Fiddle Example
If you're ok with contenteditable you could try this:
span{
display: inline-block;
position: relative;
left: 50%;
transform: translateX(-50%);
}
span::before {
content: '\270D';
}
<span contenteditable='true'></span>
A possible but imperfect (needs lots of work) idea using jquery.
fiddle
$('input').bind('keypress', function(e) {
var tester = $(this).val().length;
var code = e.keyCode || e.which;
var currentWidth = $('input').css('width').slice(0, -2);
var currentWidthParsed = parseInt(currentWidth, 10);
if(code == 8) {
var newWidth = (currentWidthParsed - 8) + 'px'
$('input').css('width', newWidth);
} else {
var newWidth = (currentWidthParsed + 8) + 'px'
$('input').css('width', newWidth);
}
});
body {
text-align: center;
}
input{
text-align: left;
border: none;
outline: none;
background-color: transparent;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<span>
✍
</span>
<input type="text">
As far as I know you can't have dynamic width of inputs with something like width: auto. In that case you could have a wrapper with fixed with and a text-align right.
So I would say the only possibility is to have that icon inside the value of the input (if it may exist as UTF-8 icon) and then strip it out when processing the value. But of course this would seem dirty.

Hover over words in a text

What would be the best way to display a hover popup with a 20-30 words definition of each word in a foreign-language text?
Right now I am using an iframe:
<span class="tooltip">foreign-language-verb
<span class="tooltiptext">
2nd pers. sing. past tense, active mood.
<iframe class="tooltip" src="general_dictionary_definition_of_the_verb.html"></iframe>
</span>
</span>
It works but the page is then very slow to load and there seems to be a limit to the number of possible iframe's: they don't display anymore if the text is too long.
Any other solution, using javascript to load the text or something?
Thanks.
EDIT:
Following up on Richard P's remark: does that mean replacing iframe with javascript loading by hand, does that make sense, is that best practices? Would that be faster than the iframe's which are very slow to load?
Taking Javascript - read local text file into account:
<script type="text/javascript">
function loadDictionaryDefinitions()
{
var elements = document.getElementsByClassName("DictionaryDefinition");
for (var i = 0; i < elements.length; i++)
elements[i].innerHTML = readTextFile("file://" + elements[i].getAttribute("filename_of_dic_definition"));
}
function readTextFile(file)
{
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
alert(allText);
}
}
}
rawFile.send(null);
}
</script>
and add:
<body onload="loadDictionaryDefinitions()">
what about css hover ? Try this one:
https://jsfiddle.net/maky/0h0ekhj6/
/* Tooltip container */
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black;
/* If you want dots under the hoverable text */
}
/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;
/* Position the tooltip text - see examples below! */
position: absolute;
z-index: 1;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
}
You could use a popover in Bootstrap if you don't mind adding it to your project. It would require a bit of javascript but should be pretty simple. Most of the functionality of it is handled by Bootstrap.

Is there a way to change the style of a div's :after psuedoelement when hovering over it's :before psuedoelement?

Given the following css:
.myDiv:before{
content:'';
width:15px;
height:15px;
display:block;
}
.myDiv:after{
...
...
display:none;
}
and html:
<div class='myDiv'></div>
Is there a way to show the .myDiv:after psuedoelement while hovering over the :before? I know I can use the hover selector as .myDiv:hover:before but I don't know how to access the :after psuedoelement from within that selector.
You can add a new style to display the content in the :after css class although it may not be the best practice.
.myDiv:hover:after {
display:block;
}
http://jsfiddle.net/gk7R2/1/
The only close way that you can do it is if you hover the entire element like this:
.myDiv {
height: 200px;
background: red;
}
.myDiv:before {
content: '';
display: block;
height: 20px;
width: 100%;
background: blue;
}
.myDiv:hover:after {
content: '';
display: block;
height: 20px;
width: 100%;
background: blue;
}
http://jsfiddle.net/Hive7/W4ca3/
You are not able to trigger the :hover::after from executing a :hover::before. You can solve this problem with javascript though. If you're wanting to maintain a clean markup, you could create a loop within this fiddle and dynamically add placeholders behind the pseudo elements so that you can interact with them instead of trying to access pseudo elements that do not exist in the DOM.
$("head").append("<style id='pseudoElementStyle'></style>");
var setPseudoElementDisplay = function (hover) {
var content = hover ? ' after' : '';
var cssRule = '.text::after { content: "' + content + '"; }';
$('#pseudoElementStyle').text(cssRule);
};
$('.text').prepend('<span class="place-holder before">before </span>');
$('.text').append('<span class="place-holder after"> after</span>');
$('.place-holder').each(function () {
var direction;
var width = $(this).css('width');
direction = $(this).hasClass('before') ? 'left' : 'right';
$(this).css('margin-' + direction, '-' + width);
});
$('.before').mouseover(function () {
setPseudoElementDisplay(true);
}).mouseout(function () {
setPseudoElementDisplay(false);
});
http://jsfiddle.net/jasonjohnson115/2d96N/

How can I make an Upvote/Downvote button?

I'm trying to make an upvote/downvote the same way that it's done on SO and Reddit, from what I can see they use arrow images as backgrounds and then position it, but I'm a CSS newbie and I need someone to walk me through it.
You could do it by adding a different picture to the background, one for every state of the button. There is however a cleaner, easier, more modern way of achieving this result: Sprites.
A sprite is an image that is saved as a part of a larger image. One of the biggest advantages of using sprites is the reduction of round-trips to the server for all the images to just one request for the Sprites. The element to display a picture has the image as background. The background is moved relative to the element so the element displays only part of the image. Like when you move a photo-frame over a poster (or in this case: moving the poster under the frame)
At SO they make an image that contains all the states for the button. They give the element for the button (a span in this case) a fixed width and height and add the background to it with CSS. Then toggle a class for the state (on or off) with javascript on the click event. Now the only thing you have to do in CSS is change the position of the background with CSS classes:
for (const btn of document.querySelectorAll('.vote')) {
btn.addEventListener('click', event => {
event.currentTarget.classList.toggle('on');
});
}
.vote {
display: inline-block;
overflow: hidden;
width: 40px;
height: 25px;
cursor: pointer;
background: url('http://i.stack.imgur.com/iqN2k.png');
background-position: 0 -25px;
}
.vote.on {
background-position: 0 2px;
}
Click to vote (using sprites): <span class="sprite vote"> </span>
You can easily add more states to the sprites like 'hover' and 'active' just the same way. SO even puts all the images for the whole page in a single image. You can verify this with firebug or the Chrome developer tools. Look for 'sprites.png'.
Update (2020)
It's been 10 years since I answered this question and in this time,
the landscape has changed. Now you can use inline svg as well to achieve this effect. I've updated the code snippet to use svg. This is how stackoverflow currently does this.
It works by toggling the color property of a surrounding span element on button click. The span element contains an inline svg image of an arrow. The fill property of the path that makes up the arrow is initialized with currentColor, which instructs it to take whatever is the current text color.
for (const btn of document.querySelectorAll('.vote')) {
btn.addEventListener('click', event => {
event.currentTarget.classList.toggle('on');
});
}
.vote {
display: inline-block;
cursor: pointer;
color: #687074
}
.vote.on {
color: #f48024
}
Click to vote (using svg):
<span class="vote">
<svg width="36" height="36">
<path d="M2 10h32L18 26 2 10z" fill="currentColor"></path>
</svg>
</span>
You can do it by using two simple images ... design two images in some image editors like Photoshop, if u don't have MSPaint...
CSS code is
#voting{
width:30px;
height:40px;
}
.upvote{
width:30px;
height: 20px;
cursor: pointer;
}
.downvote{
width:30px;
height: 20px;
background: url('downvote.jpg') 0 0 no-repeat;
cursor: pointer;
}
HTML code :
<div id="voting">
<div class="upvote"></div>
<div class="downvote"></div>
</div>
I'm doing project on django, and I'm trying to implement up-vote and down-vote on many posts, I've taken #Jan's code partly and finished it.
vote.html
<span onclick="like_function({{user_answer.pk}})" id="like-{{user_answer.pk}}" class="vote_up_off"></span>
<div id="counter-{{user_answer.pk}}">0</div>
<span onclick="dislike_function({{user_answer.pk}})" id="dislike-{{user_answer.pk}}" class="vote_down_off"></span>
vote.css
/* like dislike button */
.vote_up_off {
display: inline-block;
overflow: hidden;
width: 40px;
height: 25px;
cursor: pointer;
background: url(' https://i.stack.imgur.com/nxBdX.png');
background-position: 0 -25px;
margin-left: 5px;
}
.vote_up_on {
background-position: 0 2px;
display: inline-block;
overflow: hidden;
width: 40px;
height: 25px;
cursor: pointer;
background: url('https://i.stack.imgur.com/nxBdX.png');
margin-left: 5px;
}
.vote_down_off {
display: inline-block;
overflow: hidden;
width: 40px;
height: 25px;
cursor: pointer;
background: url('https://i.stack.imgur.com/vWw7n.png');
background-position: 0 -1px;
margin-top: 3px;
}
.vote_down_on {
display: inline-block;
overflow: hidden;
width: 40px;
height: 25px;
cursor: pointer;
background: url('https://i.stack.imgur.com/vWw7n.png');
background-position: 0 -28px;
margin-top: 3px;
}
vote.js
function like_function(answer_id) {
var like_button = document.getElementById('like-'+answer_id);
var dislike_button = document.getElementById('dislike-'+answer_id);
var counter_element = document.getElementById('counter-'+answer_id);
let current_counter = parseInt(counter_element.innerText);
//check if dislike is on(true) or off(false)
let dislike_state = false
if (dislike_button.className == "vote_down_on") {
dislike_state = true
}
else {
dislike_state = false
}
//if dislike is checked
if (dislike_state) {
current_counter += 2;
dislike_button.className = 'vote_down_off'
counter_element.innerText = current_counter
like_button.className = 'vote_up_on'
}
// if dislike is not checked
else {
if (like_button.className == 'vote_up_off') {
like_button.className = "vote_up_on"
current_counter += 1;
counter_element.innerText = current_counter
}
else {
like_button.className = "vote_up_off"
current_counter += -1;
counter_element.innerText = current_counter
}
}
}
function dislike_function(answer_id) {
var like_button = document.getElementById('like-'+answer_id);
var dislike_button = document.getElementById('dislike-'+answer_id);
var counter_element = document.getElementById('counter-'+answer_id);
let current_counter = parseInt(counter_element.innerText);
//check if like is on(true) or off(false)
let like_state = false
if (like_button.className == "vote_up_on") {
like_state = true
}
else {
like_state = false
}
//if like is checked
if (like_state) {
console.log('это тру лайк (лайк нажат)')
current_counter += -2;
like_button.className = 'vote_up_off'
counter_element.innerText = current_counter
dislike_button.className = "vote_down_on"
}
//if like is not checked
else {
if (dislike_button.className == 'vote_down_off') {
dislike_button.className = "vote_down_on"
current_counter += -1;
counter_element.innerText = current_counter
}
else {
dislike_button.className = "vote_down_off"
current_counter += 1;
counter_element.innerText = current_counter
}
}
}