To detect if a browser support translate3d we can use (WebKitCSSMatrix in window && m11 in new WebKitCSSMatrix())
but now that firefox support translate3d how to have a correct detection of it?
The idea would be to find a solution without using Modernizr.
I needed something similar. I wanted to test if a browser supported translate3d without using a library. I didn't find any good generic test that wasn't webkit specific. So after much experimentation, I came up with the following test. I first create a test element, assign a transform function to it, then see if the element retained the transform function.
function Has3DSupport()
{
var sTranslate3D = "translate3d(0px, 0px, 0px)";
var eTemp = document.createElement("div");
eTemp.style.cssText = " -moz-transform:" + sTranslate3D +
"; -ms-transform:" + sTranslate3D +
"; -o-transform:" + sTranslate3D +
"; -webkit-transform:" + sTranslate3D +
"; transform:" + sTranslate3D;
var rxTranslate = /translate3d\(0px, 0px, 0px\)/g;
var asSupport = eTemp.style.cssText.match(rxTranslate);
var bHasSupport = (asSupport !== null && asSupport.length == 1);
return bHasSupport;
} // Has3DSupport
The function is plenty fast for my needs: < 50 microseconds in desktop browsers, < 500 microseconds in mobile browsers.
Hope this helps.
Another option who works like a charm for me:
function has3d() {
var el = document.createElement('p'),
has3d,
transforms = {
'WebkitTransform':'-webkit-transform',
'OTransform':'-o-transform',
'MSTransform':'-ms-transform',
'MozTransform':'-moz-transform',
'Transform':'transform'
};
// Add it to the body to get the computed style.
document.body.insertBefore(el, null);
for (var t in transforms) {
if (el.style[t] !== undefined) {
el.style[t] = "translate3d(1px,1px,1px)";
has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
}
}
document.body.removeChild(el);
return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
}
Related
I wonder how can I use css/javascript to adjust the blinking cursor inside the search box with CSS?
Is it possible to replace default blinkig caret to horizontal blinking icon
I don't think it is so hard. I made a quick example, which works in most modern browsers except Safari.
It draws the caret on a canvas, and sets it as a background of the input, on a position calculated from the browsers caret position.
It checks if the browser supports the caret-color css property, and if it doesn't it doesn't do anything, because both the system caret, and our caret will be visible in the same time. From the browsers I tested, only Safari doesn't support it.
$("input").on('change blur mouseup focus keydown keyup', function(evt) {
var $el = $(evt.target);
//check if the carret can be hidden
//AFAIK from the modern mainstream browsers
//only Safari doesn't support caret-color
if (!$el.css("caret-color")) return;
var caretIndex = $el[0].selectionStart;
var textBeforeCarret = $el.val().substring(0, caretIndex);
var bgr = getBackgroundStyle($el, textBeforeCarret);
$el.css("background", bgr);
clearInterval(window.blinkInterval);
//just an examplethis should be in a module scope, not on window level
window.blinkInterval = setInterval(blink, 600);
})
function blink() {
$("input").each((index, el) => {
var $el = $(el);
if ($el.css("background-blend-mode") != "normal") {
$el.css("background-blend-mode", "normal");
} else {
$el.css("background-blend-mode", "color-burn");
}
});
}
function getBackgroundStyle($el, text) {
var fontSize = $el.css("font-size");
var fontFamily = $el.css("font-family");
var font = fontSize + " " + fontFamily;
var canvas = $el.data("carretCanvas");
//cache the canvas for performance reasons
//it is a good idea to invalidate if the input size changes because of the browser text resize/zoom)
if (canvas == null) {
canvas = document.createElement("canvas");
$el.data("carretCanvas", canvas);
var ctx = canvas.getContext("2d");
ctx.font = font;
ctx.strokeStyle = $el.css("color");
ctx.lineWidth = Math.ceil(parseInt(fontSize) / 5);
ctx.beginPath();
ctx.moveTo(0, 0);
//aproximate width of the caret
ctx.lineTo(parseInt(fontSize) / 2, 0);
ctx.stroke();
}
var offsetLeft = canvas.getContext("2d").measureText(text).width + parseInt($el.css("padding-left"));
return "#fff url(" + canvas.toDataURL() + ") no-repeat " +
(offsetLeft - $el.scrollLeft()) + "px " +
($el.height() + parseInt($el.css("padding-top"))) + "px";
}
input {
caret-color: transparent;
padding: 3px;
font-size: 15px;
color: #2795EE;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
If there is interest, I can clean it a bit and wrap it in a jQuery plugin.
Edit: forgot about the blinking, so I added it. A better way will be to add it as css animation, in this case the caret should be in a separate html element positioned over the input.
Changing the color of the caret is supported by the latest standards. But not changing its width is not, which I think is a shame because it is a question of accessibility for vision-impaired people.
One approach for implementing such a change yourself is first trying to figure out what is the position the caret is blinking at, then overlaying it with an element that looks like the caret but is perhaps wider etc.
Here's an article on how to go about doing such a thing. It's a good article but the end-solution is kind of complicated as a whole. But see if it solves your problem:
https://medium.com/#jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
Here is perhaps a simpler explanation for how to find the care x-y position:
How do I get the (x, y) pixel coordinates of the caret in text boxes?
note: I do not have access to the HTML or javascript code
I am using the excellent Chrome plugin, Web Override, to improve usability on a vendor site my company uses. I am only looking for CSS solutions (or possibly js/jq scripts I can sideload).
I'm trying to set table rows to highlight on hover, which is easy enough:
#task-list-main-table tr:hover {
background-color: lightyellow;
}
The problem is that there is a little button that appears on each row when you hover over it. This means if I hover over the button, the corresponding row is not highlighted.
Good:
Bad:
I know I could use pointer-events:none but then I can no longer click on the button, which I need to be able to do.
So, is there any way in CSS to "pass through" hover events without affecting click events?
This is a pretty convoluted method, but if you have the ability to inject javascript, this function will check if your mouse is overlapping whatever element you supply as the selector.
https://jsfiddle.net/tr_santi/aegybp6n/8/
//Change this value to desired element
var hoverElement = "td";
//Change this value to the class you'd like to add when hovering
var addClass = "hover";
function getOffset( el ) {
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft;
_y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
function hasClass(element, cls) {
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
function overlapListener(element, x, y, classToAdd) {
var eTop = getOffset(element).top;
var eLeft = getOffset(element).left;
var eBottom = eTop + element.clientHeight;
var eRight = eLeft + element.clientWidth;
if (x <= eRight && x >= eLeft && y <= eBottom && y >= eTop) {
if (!hasClass(element, classToAdd)) {
element.className = classToAdd;
}
} else {
if (hasClass(element, classToAdd)) {
element.className = "";
}
}
}
var elementList = document.querySelectorAll(hoverElement);
document.onmousemove=function(e){
[].forEach.call(elementList, function(b) {
overlapListener(b, e.clientX, e.clientY, addClass)
});
};
I'm sure there are some JS gurus around here that could write you something a bit less obfuscated, however I found this to be a good practice exercise for myself. I chose to write it in vanilla JS as I'm unsure of what your limitations are, although JQuery could substantially reduce the amount of needed code.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have this animation where I want the image to scale and translate based on where the mouse is over the image.
This works in Chrome and Safari but in Chrome it waits for the mouse to stop moving before applying the transition http://codepen.io/mhkeller/pen/ZbdGQb
If I remove the 400ms transition time, the transition properly updates on mousemove in Chrome http://codepen.io/mhkeller/pen/GpbJrY
I'd like to preserve the transition if possible. I've tried adding backface-visibility: hidden; and the translate3d(0,0,0) trick but it doesn't seem to work.
HTML (jade template)
#pages
.page
img(src="https://raw.githubusercontent.com/ajam/pulp/master/imgs/pages/page-3.jpg")
CSS (stylus that becomes prefixed)
.page
width 250px
img
width 100%
transition transform 400ms cubic-bezier(0,0,.2,1) // This works when
JS
function Scale(){
function Normalizer(min, max){
return function(val) {
return (val - min) / (max - min);
}
}
function Interpolater(min, max, clamp){
return function(val) {
val = min + (max - min) * val;
return clamp ? Math.min(Math.max(val, min), max) : val;
}
}
var domain = new Normalizer(0, 1);
var range = new Interpolater(0, 1);
var s = function(val){
return range(domain(val));
};
s.domain = function(min, max){
if (!arguments.length) return domain;
domain = new Normalizer(min, max)
return s
};
s.range = function(min, max, clamp){
if (!arguments.length) return range;
range = new Interpolater(min, max, clamp)
return s
};
return s;
}
var settings = {
"desktopHoverZoomOptions": {
"scale": 1.5, // How much you want it to zoom
"fit": .96, // A value between 0 and 1. Defaults to 1. Set this to something around .96 if you want to cut off the edges a little bit, like in this demo. This setting is useful if you have white space around your panels
"padding": .25 // A value between 0 and .5. Sometimes you don't want the mouse to have to reach the edge of the page to fully zoom. Setting this to something like .25 will mean you've reached the edge of the zoomed in image when you're within 25% of the page edge.
}
}
$('#pages').on('mousemove', '.page', function(e){
var scale_value = settings.desktopHoverZoomOptions.scale,
fit = settings.desktopHoverZoomOptions.fit*100,
padding = settings.desktopHoverZoomOptions.padding,
$page = $(this),
$hover_img = $page.find('img'),
page_width = $page.width(),
page_height = $page.height(),
adjusted_x = e.pageX - $page.offset().left,
adjusted_y = e.pageY - $page.offset().top,
x_perc = adjusted_x / page_width,
y_perc = adjusted_y / page_height;
var translate_percentage = fit*((page_width*scale_value - page_width)/2)/page_width;
var scale = new Scale().domain(1- padding, padding)
.range(-1*translate_percentage, translate_percentage, true);
var scaled_x_perc = scale(x_perc),
scaled_y_perc = scale(y_perc);
$hover_img.css({
'transform': 'translate('+scaled_x_perc+'%,'+scaled_y_perc+'%) scale('+scale_value+')'
});
});
I fixed it by changing it to a matrix transformation. Not sure why this works but Chrome, FF, and Safari display it properly.
$hover_img.css({
'transform': 'matrix('+ scale_value +', 0, 0, '+ scale_value +', ' + scaled_x_perc/100*page_width + ', ' + scaled_y_perc/100*page_height + ')'
});
I have a select list where the text within the options is too long as is getting cropped. Is it possible to make the text wrap instead so that all of it is visible?
http://jsfiddle.net/W4KG7/
<select>
<option>This is option 1</option>
<option>This is option 2</option>
</select>
select {
width: 92px;
}
select {
width: 92px;
white-space:pre-wrap;
}
This only appears to work in Google Chrome.
https://developer.mozilla.org/en-US/docs/Web/CSS/white-space
It seems there is no way to accomplish this in Firefox without reinventing the wheel.
The solution I have come up with achieves this for other browsers, and uses an ellipsis in Firefox:
select {
max-width: 100%;
white-space: normal;
/* For Firefox: */
text-overflow: ellipsis;
}
Using CSS to do this will only work in Chrome...
You can't do it just by using CSS, but you can use some jQuery for
a "look like" solution.
As you can see it behaves like you wanted - I'm wrapping the select box with a DIV
and adding another one that will overlap the select box - he takes the select box fixed width minus
the button of the select box. Now I'm assigning to this div the same appearance as the select box +
The selected value.
Every time the select box will be changed the new value will be set in the mask we created and
the calculated new height will be set to the select box to.
Here is the jQuery code:
$(function(){
var mYbrowser = detectBrows();
console.log(mYbrowser[0]);
$('select').each(function(index,ele){
//get current style and fixed width:
var renderWidth = $(ele).outerWidth();
var renderWidthFixed = renderWidth;
var borderstyle = $(ele).css("border-bottom-style");
var bordercolor = $(ele).css("border-bottom-color");
var borderwidth = $(ele).css("border-bottom-width");
var font = $(ele).css("font");
var defaultValue = $(ele).val();
if (borderwidth == "0px") { borderwidth = "1px"; /*FF*/ }
$(ele).css({ cursor:"pointer" });
// set by browser (different buttons):
var borderRightParsed = borderwidth +" " + borderstyle + " " + bordercolor;
var topParsed = Math.round(parseInt(borderwidth.replace(/[^0-9\.]+/g,"")));
switch(mYbrowser[0]) {
case "MSIE": renderWidthFixed = renderWidth-28; break;
case "I": renderWidthFixed = renderWidth-28; break;
case "Chrome": renderWidthFixed = renderWidth-30; break;
case "Firefox":
renderWidthFixed = renderWidth-27;
borderRightParsed= "0";
if (index > 0) topParsed++;
break;
}
//wrap + add a overlapping layer that will hide content and calculate the correct height:
$(ele).wrap($('<div />').css({width:renderWidth, margin:0, padding:0, position:"relative"}));
$(ele).after($("<div>" + defaultValue + "</div>")
.css({
minHeight:20,
padding:"5px 0px 5px 8px",
width:renderWidthFixed,
backgroundColor:"white",
whiteSpace:"pre-wrap",
position:"absolute",
borderRight:borderRightParsed,
top:topParsed,
cursor:"default",
left:borderwidth,
font:font
})
);
//set select box new height:
setHeight(ele);
//append change behavior:
$(ele).change(function(){
$(ele).next('div').text($(ele).val());
setHeight(ele);
});
});
function setHeight(ele) {
var newHeight = $(ele).next('div').outerHeight();
$(ele).height(newHeight);
}
function detectBrows(){
var ua= navigator.userAgent, tem,
M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
return 'IE '+(tem[1] || '');
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\bOPR\/(\d+)/)
if(tem!= null) return 'Opera '+tem[1];
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
return M;
}
});
Its simple and not complicated - the problem is that the select box element behave
and look different on each browser.
I added a small quick function to detect which browser is used and fine tuning his
unique values.
This method can be Improved but that's a good starting point.
Shlomo
I have a dojo datagrid which is poulated dynamically. I want to add tooltip to table headers of this datagrid. How can i do that?My datagrid simply has the structure of table and table headers. the fields get populated dynamically.
Thanks,
Sreenivas
Easiest Way
The easiest way, (Without overriding the template) would be to add a domNode to your layout header definition. So for example, when you are setting the "name" for your column in the layout, you can have something like ...
var layout = [
{
cells: [
{
name:"<i id="sometooltip" class='icon-large icon-edit'></i> Col",
field: "_item",
formatter: lang.hitch( this, this.formatter )
}
]
}];
What you then want to do is in your formatter, you want to check to see if "sometooltip" has be initialized as a tooltip, and do your connect.. You can use any tooltip.. not just dijit.Tooltip.
There are a few words of caution though. Because the formatter will run every time there is a redraw on your grid, you might want to think up better ways of creating your tooltip. For instance, you might want to add it to onGridRowHeaderHover, or you might want to just use CSS3 and use [title] attribute to create a CSS3 header.
Also. You can't just create the tooltip once, because the header is constantly rebuilt every redraw/change of data.
The Correct Way
The correct way would be to override the Grid template for the header, and include your tooltip in there. You would then extend the header equivalent of onStyleRow (which I can't remember), but basically the method that places the headers, and create your tooltip then.
I would definitely use the second option by overriding the template. Because otherwise you will find the grid glitchy.
For a pre-AMD Dojo version this is the monkey patch that we included in our globally scoped javascript resource. My other answer was after we switched to an AMD Dojo version.
// HeaderBuilder.generateHtml
// If showTooltips is true, the header contents will be used as the tooltip text.
var old_HeaderBuilder_generateHtml = dojox.grid._HeaderBuilder.prototype.generateHtml;
dojox.grid._HeaderBuilder.prototype.generateHtml = function(inGetValue, inValue){
var html = this.getTableArray(), cells = this.view.structure.cells;
dojox.grid.util.fire(this.view, "onBeforeRow", [-1, cells]);
for(var j=0, row; (row=cells[j]); j++){
if(row.hidden){
continue;
}
html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
for(var i=0, cell, markup; (cell=row[i]); i++){
cell.customClasses = [];
cell.customStyles = [];
if(this.view.simpleStructure){
if(cell.headerClasses){
if(cell.headerClasses.indexOf('dojoDndItem') == -1){
cell.headerClasses += ' dojoDndItem';
}
}else{
cell.headerClasses = 'dojoDndItem';
}
if(cell.attrs){
if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
}
}else{
cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
}
}
markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
// content
markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
// set the tooltip for this header to the same name as the header itself
try {
markup[5] = markup[5].replace("class","title='"+cell.name+"' class");
} catch(e) {
console.debug(e);
}
// styles
markup[3] = cell.customStyles.join(';');
// classes
markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
html.push(markup.join(''));
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
};
I had a similar requirement. I wanted each DataGrid column header to use the name given to the column as the tooltip since our DataGrids weren't always showing the full column name due to the columns' widths sometimes being squeezed. I added a monkey patch (below) that is done with an AMD Dojo version:
require(
[
"dojo/dom",
"dojox/grid/DataGrid",
"dijit/_Widget",
"dijit/form/FilteringSelect",
"dijit/form/MultiSelect",
"dijit/layout/ContentPane",
"dijit/layout/TabContainer",
"dojox/grid/_Grid",
"dijit/MenuItem",
"dijit/MenuSeparator",
"dojox/grid/_Builder",
"dojox/grid/cells/_base",
"dojox/grid/util",
"dojo/parser",
"dojo/_base/array",
"dojo/_base/lang",
"dojo/ready",
"dojo/query",
"dijit/registry",
],
function(dom, dojox_grid_DataGrid, dijit__Widget, dijit_form_FilteringSelect,
dijit_form_MultiSelect, dijit_layout_ContentPane, dijit_layout_TabContainer,
dojox_grid__Grid, MenuItem, MenuSeparator, dojox_grid__Builder,
dojox_grid_cells__Base, dojox_grid_util,
parser, array, dojoLang, ready, dojoQuery, registry) {
var old_HeaderBuilder_generateHtml = dojox_grid__Builder._HeaderBuilder.prototype.generateHtml;
dojox_grid__Builder._HeaderBuilder.prototype.generateHtml = function(inGetValue, inValue){
var html = this.getTableArray(), cells = this.view.structure.cells;
dojox_grid_util.fire(this.view, "onBeforeRow", [-1, cells]);
for(var j=0, row; (row=cells[j]); j++){
if(row.hidden){
continue;
}
html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
for(var i=0, cell, markup; (cell=row[i]); i++){
cell.customClasses = [];
cell.customStyles = [];
if(this.view.simpleStructure){
if(cell.headerClasses){
if(cell.headerClasses.indexOf('dojoDndItem') == -1){
cell.headerClasses += ' dojoDndItem';
}
}else{
cell.headerClasses = 'dojoDndItem';
}
if(cell.attrs){
if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
}
}else{
cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
}
}
markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
// content
markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
// set the tooltip for this header to the same name as the header itself
markup[5] = markup[5].replace("class","title='"+cell.name+"' class");
// styles
markup[3] = cell.customStyles.join(';');
// classes
markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
html.push(markup.join(''));
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
};
}
);
Note that if there's any chance that any markup may be added to the cell.name then you'll need to add a condition that will somehow extract just the text from it to be the tooltip, or somehow generate a tooltip that won't throw a rendering error, or avoid setting a tooltip altogether for that column.