I am unable to see the contents of the image tool tip when focussed on it using keyboard. Below is a code example:
<img id= "id1" title ="title1" tabindex ="0" src="/images/home.gif" alt="title1" />
I am able to see the tool tip contents when hovered using mouse.
Short Answer
Don't use the title attribute, it doesn't serve any purpose that wouldn't be better suited as a caption under an image or a <label> on an <input> (please don't use a title on an input....even for a search box, even 'placeholder' text is preferable as at least some screen readers will read that and your touch screen users will still be able to read what the input is for).
Medium Answer
The title attribute has low support, offers very little to people in the modern age of touch screens (it is only sighted mouse users who don't use magnifiers or other assistive tech who gain anything from a title attribute) and in general is not a good idea for most use cases.
As a general rule if you do want to use it (so mouse users can see what an image is about) then make sure it is the same as the alt attribute so that you are providing the same information / experience to screen reader users as non screen reader users.
Long Answer
We played with this for a while, there are some circumstances where the title attribute (or at least the effect of revealing extra information about an image) can be useful. In the end we 'rolled our own' version of the title attribute that allowed us to have additional information about a picture, without interrupting the flow of a document with a caption.
In the example below (a stripped back version of what we use) we have:-
Made it accessible via keyboard and on hover.
Provided useful information to those who need it, that has the added benefit of being accessible (as title tooltips don't follow minimum sizing guidelines in some browsers and don't scale even if you change the font size settings in your browser).
Made it work on touch devices.
Designed to function like a plugin, in that you produce standard markup and a little bit of JavaScript and CSS magic does the rest.
It still isn't as good as simply providing a caption under the image but I believe it captures the spirit of what the 'title' attribute on an image is designed for, while accounting for accessibility and technology changes from when it was introduced.
Please Note - the first 80 or so lines of JavaScript are just a small helper library that allows jQuery style syntax, the relevant part starts at $("img").each(function(){.
//tiny replacement for jQuery - adapted version of ki.js
!function (b, c, d, e, f) {
f = b['add' + e]
function i(a, d, i) {
for(d = (a && a.nodeType ? [a] : '' + a === a ? b.querySelectorAll(a) : c), i = d.length; i--; c.unshift.call(this, d[i]));
}
$ = function (a) {
return /^f/.test(typeof a) ? /in/.test(b.readyState) ? setTimeout(function() { $(a); }, 9) : a() : new i(a);
};
$[d] = i[d] = {
on: function (a, b) {
return this.each(function (c) {
f ? c['add' + e](a, b, false) : c.attachEvent('on' + a, b)
})
},
off: function (a, b) {
return this.each(function (c) {
f ? c['remove' + e](a, b) : c.detachEvent('on' + a, b)
})
},
each: function (a, b) {
for (var c = this, d = 0, e = c.length; d < e; ++d) {
a.call(b || c[d], c[d], d, c)
}
return c
},
splice: c.splice
}
}(document, [], 'prototype', 'EventListener');
$.each = function(arr, callback) {
if(toString.call(arr) === '[object Array]'){
var i = 0, l = arr.length;
for(; i < l; ++i) {
callback.call(arr[i], i, arr[i]);
}
} else {
for (i in arr)
callback.call(arr[i], i, arr[i]);
}
return arr;
};
//extended to include "attr"
$.prototype.attr = function(a, b) {
return b === []._ ? this[0].getAttribute(a) : this.each(function(c) {
c.setAttribute(a, b);
});
};
//extended to include "removeAttr"
$.prototype.removeAttr = function(a) {
return this.each(function(b) {
b.removeAttribute(a);
});
};
//extend to include "parent"
$.prototype.parent = function() {
return (this.length < 2) ? $(this[0].parentNode): [];
};
//custom function to wrap an element in another
$.prototype.wrap = function(a) {
return this.each(function(b) {
var c = document.createElement(a)
b.parentNode.insertBefore(c, b);
c.appendChild(b);
});
};
//quick way of exposing everything like 'addClass', 'removeClass' etc. without having to define each one indivdually
var props = ['add', 'remove', 'toggle', 'has'],
maps = ['add', 'remove', 'toggle', 'contains'];
props.forEach(function(prop, index) {
$.prototype[prop + 'Class'] = function(a) {
return this.each(function(b) {
if(a){
b.classList[maps[index]](a);
}
});
};
});
//extend to include "after"
$.prototype.after = function(a) {
return this.each(function(b) {
b.insertAdjacentHTML('afterend', a);
});
};
//Below is the actual function, all of the above is just a simple replacement for jQuery.
//Should work with just jQuery but you would have to check.
$("img").each(function(){
$(this).wrap("div"); //create a div around an image
var title = $(this).attr("title"); //grab the title
var wrapper = $(this).parent(); //grab the div we just created
wrapper.attr("data-title", title); //set the data-title that we use in the CSS on the wrapper
wrapper.addClass("image"); //add the class that we use for CSS
wrapper.attr("tabindex", "0"); //make the div focusable with tabindex="0"
$(this).after('<span class="visually-hidden">, Title ' + title + '</span>'); //add a span with the title in that is accessible to screen readers - note the use of a comma before the 'Title' part as this makes it more natural (as we are 'hacking' an experience similar to that of a screen reader reading an actual title.)
$(this).removeAttr('title'); //remove the actual title, otherwise some screen readers will announce the title twice.
});
.image{
display:block;
overflow:hidden;
}
/*need relative position in order to absolutely position the overlay*/
.image {
position:relative;
width:200px;
height:200px;
margin: 10px;
}
.image img {
width:100%;
vertical-align:top;
}
/*add a transition*/
.image:after,
.image:before {
position:absolute;
opacity:0;
transition: all 0.5s;
}
/*remove the transition for people who have reduced motion as a preference*/
#media (prefers-reduced-motion: reduce) {
.image:after,
.image:before {
transition: none;
}
}
/*create an overlay*/
.image:after {
content:'';
width:100%;
height:100%;
top:0;
left:0;
background:rgba(0,0,0,0.4);
}
/*create a box at the bottom that contains the 'data-title' text that was added to the div we created*/
.image:before {
content: attr(data-title);
font-size: 1.25rem;
line-height: 1.9rem;
width:100%;
color:#fff;
z-index:1;
bottom:0;
padding:4px 10px;
text-align:left;
background:black;
box-sizing:border-box;
-moz-box-sizing:border-box;
}
/*make the overlay visible on hover and focus*/
.image:hover::after,
.image:hover::before,
.image:focus::after,
.image:focus::before{
opacity:1;
}
/*put a border around on focus*/
.image:focus{
outline: 2px solid #333;
outline-offset: 4px;
}
/*visually hidden class used to make text screen reader accessible but not visible*/
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<img src="https://via.placeholder.com/150" title="First Image" alt="First Image"/>
<img src="https://via.placeholder.com/150" title="Second Image, A Longer Text Test for a more complex title, adjust to your needs" alt="Second Image"/>
According to the HTML 5.2 specification,
The title attribute represents advisory information for the element, such as would be appropriate for a tooltip.
The specification also adds the following warning:
Warning! Relying on the title attribute is currently discouraged as many user agents do not expose the attribute in an accessible manner as required by this specification (e.g., requiring a pointing device such as a mouse to cause a tooltip to appear, which excludes keyboard-only users and touch-only users, such as anyone with a modern phone or tablet).
In other words, one should not rely on the title attribute for exposing information to keyboard users, including screen reader users. This issue has been around for many years. Accessibility standards recommend(ed) the use of the title attribute only on the frame element (which is deprecated in HTML 5) the input element (if you don't use a label element for aesthetic reasons) and the abbr element. See also Steve Faulkner's blogpost Using the HTML title attribute – updated. (Even though the blogpost was last updated in 2013, the advice is essentially still valid.)
If you want the content of the title attribute to be exposed visually on keyboard focus, you'll need to rely on CSS, JavaScript or a combination of both. Note, however, that the img element is not keyboard focusable by default.
Related
I'm considering using Blazor Hybrid to rewrite my app. So far, I'm loving the productivity, but one of the core features is image processing.
To check whether the Blazor Hybrid is a valid option, I created a sample WPF app, added Blazor and I noticed that just binding to a source of <img> tag is extremely slow.
Here is a component I created:
#using System.Reactive.Subjects
#using System.Reactive
#using System.Reactive.Linq
#using SkiaSharp
#using MudBlazor
<h3>FollowCursor</h3>
<MudCheckBox #bind-Checked="#hideImage">Hide image with opacity</MudCheckBox>
<MudCheckBox #bind-Checked="#useVisibillityHidden">Visibillity hidden</MudCheckBox>
<MudCheckBox #bind-Checked="#useImageSource">Use image source</MudCheckBox>
<MudCheckBox #bind-Checked="#disableStateHasChangedOnMove">Disable StateHasChanged on move</MudCheckBox>
<p>Mouse position: #MousePosition</p>
<p>Image size: #ImageSize</p>
<div style="width: 100%; height: 500px;border: solid green 1px" #ref="Img" #onmousemove="disableStateHasChangedOnMove ? EventUtil.AsNonRenderingEventHandler<MouseEventArgs>(onMouseMove) : onMouseMove">
<img src="#ImageSource" style="height: 100%; width: 100%; margin: auto; border: solid red 1px;opacity: #(hideImage ? 0 : 1); visibility: #(useVisibillityHidden ? "hidden" : "visible")"
/>
</div>
#code {
public ElementReference Img { get; set; }
public string? ImageSource
{
get => useImageSource ? _imageSource : null;
set => _imageSource = value;
}
public SKPoint MousePosition { get; set; }
public SKSize ImageSize { get; set; }
Subject<Unit> _mouseMove = new();
private string? _imageSource;
bool useImageSource = true;
bool hideImage = false;
bool useVisibillityHidden = false;
bool disableStateHasChangedOnMove = true;
protected override async Task OnInitializedAsync()
{
StateHasChanged();
_mouseMove
// .Sample(TimeSpan.FromMilliseconds(1))
.Do(async _ =>
{
var drawMousePosition = DrawMousePosition();
await InvokeAsync(() =>
{
ImageSource = drawMousePosition;
if (disableStateHasChangedOnMove)
{
StateHasChanged();
}
});
}).Subscribe();
}
private string DrawMousePosition()
{
var bmp = new SKBitmap((int)ImageSize.Width, (int)ImageSize.Height);
using var canvas = new SKCanvas(bmp);
canvas.Clear(SKColors.White);
canvas.DrawCircle(MousePosition.X, MousePosition.Y, 10, new SKPaint
{
Color = SKColors.Red,
Style = SKPaintStyle.Fill
});
canvas.Save();
return ToBase64Image(bmp);
}
private async Task onMouseMove(MouseEventArgs e)
{
MousePosition = new SKPoint((float)e.OffsetX, (float)e.OffsetY);
_mouseMove.OnNext(Unit.Default);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
var rect = await Img.MudGetBoundingClientRectAsync();
ImageSize = new SKSize((float)rect.Width, (float)rect.Height);
}
public static string ToBase64Image( SKBitmap bmp)
{
using var image = SKImage.FromBitmap(bmp);
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
return "data:image/png;base64," + Convert.ToBase64String(data.ToArray());
}
}
Its job is to draw a circle under your cursor. This is how I achieved various drawing tools in the WPF app I am trying to replace - for example when you are drawing a line, I generate a preview image every time your mouse moves and refresh it. When LMB is released, latest preview replaces the edited image.
In WPF or AvaloniaUI this approach works extremely well.
In Blazor, it is really slow. I believe that the reason is converting base64 image to a bitmap in the BlazorWebView is the bottleneck, you can verify with the checkboxes. Also, I know its a good idea to silence the autotriggering of StateHasChanged on mouse move, but the result still isn't great.
Is there a better way to do this? I know that there is a special high performance view component for SkiaSharp, but it works only with Blazor WA - it is based on reusing memory between renderer and the bitmap itself. Not possible in Hybrid and server. There is an option of creating this in Blazor WA and publishing it as a custom component and embeding it in the Hybrid app, but it seems like a weird workaround.
As an alternative, I know that I can create the image editing part in the host tech for Hybrid (like maui to get multiplatform support), and show it on top of when needed, but maybe there is a way to do this in Blazor.
I found some canvas wrappers, but they still require to create the img tag with bound source, and this is the slowest part.
Any suggestions? Maybe the whole idea behind how to draw the preview is wrong?
For such a scenario you should use a javascript implementation and just steer/set the point on the client's browser. That way you avoid sending massive data to the client and all the dom-diffing that is so time consuming.
I encounter some design problems.
I have a page with a JQuery Calendar (full-calendar) and I need to retrieve two IDs depending on the current month.
Which is the best solution ?
Retrieve the IDs using an Ajax Request each time the calendar is re-rendered (the month changed)
Loading all the Ids (I use Asp.Net Mvc) once and then filtering.
I tried to use the first solution but when the user switch the month too fast (January to February per example), it affects January IDs to February because the user switched too fast (before the first requests actually finished).
Hope I'm clear.
Thank you in advance.
The First Method is prefereable. What you can do is add a time disable ,for me a loader is of best usage in this type of situations
Css :
body.loading {
overflow: hidden;
}
body.loading .modal1 {
display: block;
}
.modal1 {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 255, 255, 255, .8 )
url('Loaderurl')
50% 50%
no-repeat;
}
View -
add this at bottom
<div class="modal1"></div>
Script-
$body = $("body");
$(document).on({
ajaxStart: function () {
$body.addClass("loading");
},
ajaxStop: function (e) {
$body.removeClass("loading");
}
});
Thanks for the help.
What I chose to do is to initialize an array where I put all the needToCancel ajax requests and created a cancelAjaxRequests method that I call each time I change the month.
var lastMonthAjaxRequests = [];
lastMonthAjaxRequests.push(... my ajax requests...)
function abortAjaxRequests(ajaxRequests) {
$.each(ajaxRequests,
function() {
this.abort();
});
}
Then each time my calendar is re-rendered :
abortAjaxRequests(lastMonthAjaxRequests);
lastMonthAjaxRequests = [];
I have a table which I create programatically in my code behind file and set the colours of alternate row to gray for easier visibility like so:
<New cells and rows created here>
tblResults.GridLines = GridLines.Both;
tblResults.BorderStyle = BorderStyle.Solid;
tblResults.HorizontalAlign = HorizontalAlign.Center;
if (rowNumber % 2 == 1)
{
tblRow.BackColor = System.Drawing.Color.LightGray;
}
tblResults.Rows.Add(tblRow);
tblResults.CssClass = "myclass" ;
pnlContent.Controls.Add(tblResults);
I also want to have the rows highlighted when a user hovers over them like so:
.myclass tr:hover
{
background: #FCF;
}
Now the hover only seems to work for the rows which are not highlighted gray from the c# code which I assumes takes precedence over the css.
How can I also make those gray rows work with the css hover?
Try this hope it helps, I think some where the Style inside the page is overwriting your light Grey Background. Try this it will be ease to find the solution
if (rowNumber % 2 == 1)
{
tblRow.Attributes.Add("Class","ClassName_grey");
}
else{
tblRow.Attributes.Add("Class","ClassName_nothing")
}
.myclass tr:hover
{
background: #FCF;
}
.ClassName_grey {
background: #eeeeee;
}
You might try
.myclass tr:hover
{
background-color: #FCF;
}
Or adding the !important qualifier. The former is basically setting the same style as the server-side code should be, whereas your code was setting the less specific background (all aspects of it, not just colour).
Otherwise try viewing the source or using developer tools to see what style attribute you need to overwrite.
I am making a web page in asp.net c# and I want to change the border color of textbox when it fails the validation.
For example :
Please tell me how can I do this.
Thanks.
This sulation is easy, but a little bit dirty:
Specify an onClientClick attribute on your button and this JavaScript-Function
<script type="text/javascript">
function YourButtonClickEvent() {
var validation = Page_ClientValidate();
if (!validation) {
for (var i = 0; i < Page_Validators.length; i++) {
if (!Page_Validators[i].isvalid) {
$("#" + Page_Validators[i].controltovalidate).css("border-color", "red");
}
}
}
return val;
}
</script>
using jQuery -- use on blur Event
if(!validation)
{
$('textboxid').css('border','1px solid red');
}
else
{
$('textboxid').css('border','1px solid black'); //set to normal color
}
using Javascript -- use on Blur event
document.getElementById('textboxId').Style.Border = "1px solid red";
For more information go through this link
I make a tablecell using C# in my code behind, and I add a CSS class to the label inside the cell to rotate it:
.vertical {color:#333;
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
-webkit-transform:rotate(270deg);
-moz-transform:rotate(270deg);
-o-transform: rotate(270deg);
white-space:nowrap;
display:block;
}
The problem is that after I rotate my label, my table cell (and table) have not resized to fit the new text. Is there a way using CSS or an attribute I can use to have my table re-size automatically to fit the new content?
I'd appreciate any help.
---EDIT---
So after playing around with some the CSS class, I realized the source of my problem. Basically, after I apply CSS changes - my tables don't resize. They still size as if the content was not modified.
Is it possible to make my tables re-size after the CSS style changes the size of my tablecells?
You need to calculate the new height of your Label and then set it's containing element to that height. This fiddle is what I am talking about.
<table>
<tr>
<td id="someLabel" class="vertical">some stuff</td>
<td>some other stuff sljk fkas jd</td>
</tr>
...
</table>
and then using jQuery
$.fn.textWidth = function () {
var html_org = $(this).html();
var html_calc = '<span>' + html_org + '</span>';
$(this).html(html_calc);
var width = $(this).find('span:first').width();
$(this).html(html_org);
return width;
};
$(function(){
var someLabelSize = $("#someLabel").textWidth();
$("#someLabel").css("height", (someLabelSize + 5));
});
Just change the selectors to reflect your needs.