开发者

Can I customize the in-browser tool tip bubble?

开发者 https://www.devze.com 2023-03-20 07:15 出处:网络
Is their a way to customize the way the tool tip bubbles look like, cross browser? For example, when I hover over a tag that has a title attribute, Firefox displays a tool tip bubble. I\'d like to cu

Is their a way to customize the way the tool tip bubbles look like, cross browser?

For example, when I hover over a tag that has a title attribute, Firefox displays a tool tip bubble. I'd like to customize that to look just like the rest of the site.

Is there a CSS3 hack into that? And if not, can I replace it with something that will work automatically on all the elements with a title attribute?

<a href="" title="This is a nice link, click here"/&g开发者_运维技巧t; <div onclick="" title="A nice action button"/>

Image example:

Can I customize the in-browser tool tip bubble?

I'm working real hard on getting my site good looking and ready for service. One of things I noticed was the tooltip breaks my style, just a little... but I'm nuts about those kinds of stuff. Yes I'm still working on it - http://pagelook.us. Huge work in process. Hover over any of the navigation buttons for an active example.


I just wanted to point out that the tooltip displayed for titles is usually the one built into the operating system, and the browser doesn't provide a CSS interface to override the operating system defaults.

Often, the browser doesn't even modify the behaviour of that look and feel for itself.


There is nothing on CSS that can be used to customize a tooltip. You'll have to use Javascript or any other JS framework to reach that. Currently, there are hundreds of different jQuery and Mootools snippets out there that you can download for free and customize at your own needs.


I’m not aware of any browser extensions to CSS that let you customise the look of tooltips.

There are lots of jQuery tooltip plugins though, e.g.

  • http://docs.jquery.com/Plugins/tooltip

You could apply it to all HTML elements with a title attribute like this:

$("*[title]").tooltip();

(Not sure how well it would perform.)


If you do not want to use Javascript you can achieve that using pure CSS. However there may be some limits. A JS tooltip can have more features.

For example check these:

  • http://www.nitinh.com/2010/03/sexy-tooltip-using-css3/
  • http://sixrevisions.com/css/css-only-tooltips/


You can also start with that fiddle : http://jsfiddle.net/2RN6E/

And put more CSS


Sure, i developed this plugin for jQuery, you just need to include it in your page

Here is how to get it to work: http://plugins.jquery.com/project/jTitle

/*! jQuery Tooltip Plugin by Pezhvak @ IMVx.ORG
 *  Version: 1.0
 *  Tested on IE9, FF4, Safari5
 *  Description: By using this plugin all of your title attributes going to change, you may even change your tooltips in runtime
 */

(function($){
    /*
     * @groupName: [string] name of the group of titlebox
     * @ms: [milliseconds] to hide, if 0: hide when mouseout, if -1: don't hide automatically, if -2: hide when clicked on title
     * @delay: [milliseconds] to show, -1: don't show automatically
     * @mode: [string] how you want to manage your titles, single: only one toolbox allowed to be shown in each category, share: one toolbox will be shared between all elements in a group, free: each element have it's own titlebox
     * @move: [string] how titlebox appears, vertically, horizontally or static. static: without moving effect
     * @stop: [string] which side of the element titlebox should stop? on width or height?
     * @showEasing: [string] what effect to use when titlebox appears, [easeOutBounce, easeOutElastic]
     * @hideEasing: [string] what effect to use when titlebox disappears, [same as showEasing]
     * @moveEasing: [string] what effect to use when titlebox is moving to other element, [same as showEasing], it will be used only when mode is
     * @theme: [object] contains style of the titlebox
     * ! Keep in mind you may override default settings for your special elements by setting [titleMS, titleMove, titleStop, titleShowEasing, titleHideEasing, titleTheme] attribute for them.
     * ! titleTheme should contains created theme name by $.createTheme function
     */
    var option = {groupName: '_default_', 
                  ms: 5000, 
                  speed: 'slow', 
                  delay: 0, 
                  distance: 'auto', 
                  mode: 'single', 
                  move: 'horizontally', 
                  stop: 'width', 
                  recommend: 'auto', 
                  showEasing: 'easeOutBounce', 
                  hideEasing: 'easeInOutBounce', 
                  moveEasing: 'easeOutElastic', 
                  theme:{
                      shadow: '0px 0px 5px #292929', 
                      opacity: 0.8,
                      roundCorners: 5, 
                      style: {
                          color: '#fff', 
                          background: 'rgba(0,0,0, 0.8)', 
                          padding: '10px', 
                          fontSize: '12px'
                      }
                  }
    };
    var _idc = 0; // ID Counter
    var groups = {};
    var currentGroup = {};

    $.titleDefineGroup = function(group_name, options)
    {
        var option_buffer = $.extend(true, {}, option);
        groups[group_name] = $.extend(true, option_buffer, options);
        groups[group_name].groupName = group_name;
    }

    function get_image_size(image_uri)
    {
        var image = new Image();
        image.src = image_uri;
        return {width: image.width, height: image.height};
    }

    $(window).bind('load.tooltip', function(){
        $("[title]").live('mouseover.tooltip', function(){
            _idc++;
            $(this).attr('customTitle', $(this).attr('title')).attr('title', null).attr('_idc', _idc);
            this.onTitleShow = function(){} // titleShowEvent
            this.onTitleHide = function(){} // titleHideEvent
            $(this).mouseover();
        });

        $("[customTitle]").live('mouseover.tooltip', function(){
            $(this).tooltip({text: $(this).attr("customTitle")});
        });
    });

    $.fn.onTitleShow = function(fnc)
    {
        return this.each(function(){
            this.onTitleShow = fcn;
        });
    };

    $.fn.onTitleHide = function(fnc)
    {
        return this.each(function(){
            this.onTitleHide = fnc;
        });
    };

    $.fn.showTitle = function()
    {
        return this.each(function(){
            if($(this).attr("customTitle")!="")
            {
                _idc++;
                $(this).attr('customTitle', $(this).attr('title')).attr('title', null).attr('_idc', _idc);
                this.onTitleShow = function(){} // titleShowEvent
                this.onTitleHide = function(){} // titleHideEvent
                $(this).tooltip({text: $(this).attr("customTitle"), forced: true});
            }
        });
    }

    $.titleSettings = function(options)
    {
        $.extend(true, option, options);
    };

    function _tooltip_generate_arrow(side)
    {
        var canvas = document.createElement('canvas');
        if(!canvas.getContext) return;
        var canvasContext = canvas.getContext('2d');
        canvasContext.beginPath();
        switch(side)
        {
            case "up":{
                canvas.width = '8';
                canvas.height = '6';

                canvasContext.moveTo(4,0);
                canvasContext.lineTo(8,6);
                canvasContext.lineTo(0,6);
                canvasContext.lineTo(4,0);

            }break;
            case "down":{
                canvas.width = '8';
                canvas.height = '6';

                canvasContext.moveTo(4,6);
                canvasContext.lineTo(0,0);
                canvasContext.lineTo(8,0);
                canvasContext.lineTo(4,6);
            }break;
            case "left":{
                canvas.width = '6';
                canvas.height = '8';

                canvasContext.moveTo(0,4);
                canvasContext.lineTo(6,0);
                canvasContext.lineTo(6,8);
                canvasContext.lineTo(0,4);
            }break;
            case "right":{
                canvas.width = '6';
                canvas.height = '8';

                canvasContext.moveTo(6,4);
                canvasContext.lineTo(0,0);
                canvasContext.lineTo(0,8);
                canvasContext.lineTo(6,4);
            }break;
        }

        canvasContext.fillStyle = currentGroup.theme.style.background;
        canvasContext.fill();
        canvas.style.position = 'absolute';
        $(canvas).fadeOut(1);
        return canvas;
    }

    function _tooltip_conflict(element, tooltip)
    {
        var result = {left: false, right: false, top: false, bottom: false, leftPoint: {x: 0, y: 0, position: 'center'}, rightPoint: {x: 0, y: 0, position: 'center'}, topPoint: {x: 0, y: 0, position: 'center'}, bottomPoint: {x: 0, y: 0, position: 'center'}};
        var elementPosition = element.offset();
        var padding = parseInt(tooltip.css('padding').replace('px','')) * 2;
        if(isNaN(padding)) padding = 0;
        var tooltipWidth = tooltip.width() + padding;
        var tooltipHeight = tooltip.height() + padding;
        var arrow = '';

        // Checking left
        arrow = _tooltip_generate_arrow('right');
        if(elementPosition.left - tooltipWidth - arrow.width < 0) result.left = true;
        else{
            result.leftPoint.x = elementPosition.left - tooltipWidth - arrow.width;
            result.leftPoint.y = (tooltipHeight > element.height()) ? elementPosition.top - (tooltipHeight/2) + (element.height()/2) : elementPosition.top + (element.height()/2) - (tooltipHeight/2);
            if(result.leftPoint.y < 0) {result.leftPoint.y = elementPosition.top; result.leftPoint.position = 'top';}
            if(result.leftPoint.y + tooltipHeight > $(window).height()) {result.leftPoint.y = elementPosition.top - (tooltipHeight - element.height()); result.leftPoint.position = 'bottom';}
        }
        // Checking Right
        arrow = _tooltip_generate_arrow('left');
        if(elementPosition.left + element.width() + tooltipWidth + arrow.width > $(window).width()) result.right = true;
        else{
            result.rightPoint.x = elementPosition.left + element.width() + arrow.width;
            result.rightPoint.y = (tooltipHeight > element.height()) ? elementPosition.top - (tooltipHeight/2) + (element.height()/2) : elementPosition.top + (element.height()/2) - (tooltipHeight/2);
            if(result.rightPoint.y < 0) {result.rightPoint.y = elementPosition.top; result.rightPoint.position = 'top';}
            if(result.rightPoint.y > $(window).height()) {result.rightPoint.y = elementPosition.top - (tooltipHeight - element.height()); result.rightPoint.position = 'bottom';}
        }
        // Checking Up
        arrow = _tooltip_generate_arrow('down');
        if(elementPosition.top - tooltipHeight - arrow.height < 0) result.top = true;
        else{
            result.topPoint.x = (tooltipWidth > element.width()) ? elementPosition.left - (tooltipWidth/2) + (element.width()/2) : elementPosition.left + (element.width()/2) - (tooltipWidth/2);
            result.topPoint.y = elementPosition.top - tooltipHeight - arrow.height;
            if(result.topPoint.x < 0) {result.topPoint.x = elementPosition.left; result.topPoint.position = 'left';}
            if(result.topPoint.x+tooltipWidth > $(window).width()) {result.topPoint.x = elementPosition.left - (tooltipWidth - element.width()); result.topPoint.position = 'right';}
        }
        // Checking Down
        arrow = _tooltip_generate_arrow('up');
        if(elementPosition.top + element.height() + tooltipHeight + arrow.height > $(window).height()) result.bottom = true;
        else{
            result.bottomPoint.x = (tooltipWidth > element.width()) ? elementPosition.left - (tooltipWidth/2) + (element.width()/2) : elementPosition.left + (element.width()/2) - (tooltipWidth/2);
            result.bottomPoint.y = elementPosition.top + element.height() + arrow.height;
            if(result.bottomPoint.x < 0) {result.bottomPoint.x = elementPosition.left; result.bottomPoint.position = 'left';}
            if(result.bottomPoint.x+tooltipWidth > $(window).width()) {result.bottomPoint.x = elementPosition.left - (tooltipWidth - element.width()); result.bottomPoint.position = 'right';}
        }

        return result;
    }

    function _tooltip_get_box_position()
    {

    }

    $.tooltip_proccess = function(){
        // Define
        $("[title]:not([titleGroup])").attr("titleGroup", "_default_");
        var settings = {move: 0, stop: 0, mode: 'single', recommend: 'auto', group: 'default', startPoint: {x: 0, y: 0}, endPoint: {x: 0, y: 0}}
        settings.group = (($(this).attr("titleGroup")) ? (groups[$(this).attr("titleGroup")]) ? groups[$(this).attr("titleGroup")] : option : option);
        currentGroup = settings.group;
        settings.move = (($(this).attr("titleMove")) ? $(this).attr("titleMove") : settings.group.move).toLowerCase();
        settings.stop = (($(this).attr("titleStop")) ? $(this).attr("titleStop") : settings.group.stop).toLowerCase();
        settings.recommend = (($(this).attr("titleRecommend")) ? $(this).attr("titleRecommend") : settings.group.recommend).toLowerCase();

        // Verifying
        if($(this).attr("titleActive")=="true") return; // prevent re-generation for elements which already have an active toolbox

        if(settings.group.mode != 'free')
        {
            var force_return = false;
            $("[titleGroup='"+$(this).attr("titleGroup")+"'][titleActive='true']").each(function(){
                clearTimeout(document.getElementById("toolbox_"+this.id).tooltipTimeout); // prepair to move
                clearInterval(this.onTitleChange);
                $("#toolbox_"+this.id).attr("titleActive", "false");
                if(settings.group.mode == 'single')
                {
                    this.hideTitle();
                }
                else // share
                {
                    force_return = true; // we goint to handle it from here, we don't need rest of the code ;)
                    var elementPos = $(this).offset();
                    var conflict = _tooltip_conflict($(this), $("#toolbox_"+this.id)); 
                    var padding = parseInt(($("#toolbox_"+this.id).css("padding")).replace("px", ""));
                    var DIV = document.getElementById("toolbox_"+this.id);

                    //end
                }
            });
            if(force_return) return;
        }

        // Generating TooltipBox
        $(this).attr("titleActive", "true");
        _idc++;
        var DIV = document.createElement("DIV");
        if($(this).attr("id") == "") $(this).attr("id", "auto_"+_idc);
        DIV.name = DIV.id = "toolbox_"+$(this).attr("id");
        DIV.style.position = 'absolute';
        $.extend(true, DIV.style, settings.group.theme.style);
        DIV.style.background = settings.group.theme.style.background;

        DIV.style.zIndex = 999;
        DIV.innerHTML = $(this).attr("customTitle");
        this.onTitleChange = setInterval(function(){
            if($(_this).attr("customTitle") != DIV.childNodes[0].nodeValue) DIV.childNodes[0].nodeValue = $(_this).attr("customTitle");
        }, 100);

        DIV.style.width = 'auto';
        DIV.style.height = 'auto';
        DIV.style.whiteSpace = 'nowrap';

        DIV.style['-moz-box-shadow'] = settings.group.theme.shadow;
        DIV.style['-webkit-box-shadow'] = settings.group.theme.shadow;
        DIV.style['box-shadow'] = settings.group.theme.shadow;



        if(typeof(settings.group.theme.roundCorners) != 'number') settings.group.theme.roundCorners = settings.group.theme.roundCorners.replace(/px$/i, '');
        $(DIV).fadeTo(1,1).attr('_tidc', $(this).attr('_idc')).roundCorners(settings.group.theme.roundCorners);
        document.body.appendChild(DIV);

        // Determining

        var elementPos = $(this).offset();
        var conflict = _tooltip_conflict($(this), $(DIV)); 
        var padding = parseInt(($(DIV).css("padding")).replace("px", ""));

        // Adjusting Box
        switch(settings.stop)
        {
            case "width":
            {
                switch(settings.recommend)
                {
                    case "up":
                    case "top":
                    {
                        if(conflict.top) settings.recommend = 'bottom';
                    }break;
                    case "down":
                    case "bottom":
                    {
                        if(conflict.bottom) settings.recommend = 'top';
                    }break;
                    default: // Auto
                    {
                        settings.recommend = (elementPos.top < $(window).height() / 2) ? 'bottom' : 'top';
                    }break;
                }

                if(settings.move == 'vertically')
                {
                    settings.startPoint.x = conflict[settings.recommend+'Point'].x;
                    settings.startPoint.y = settings.startPoint.y = (elementPos.top < $(window).height() / 2) ? ($(window).height() / 3) * 2 : ($(window).height() / 3);
                }
                else
                {
                    settings.startPoint.x = (elementPos.left < $(window).width() / 2) ? ($(window).width() / 3) * 2 : ($(window).width() / 3);
                    settings.startPoint.y = conflict[settings.recommend+'Point'].y;
                }
                settings.endPoint.x = conflict[settings.recommend+'Point'].x;
                settings.endPoint.y = conflict[settings.recommend+'Point'].y;
            }break;
            default:
            case "height":
            {
                switch(settings.recommend)
                {
                    case "left":
                    {
                        if(conflict.left) settings.recommend = 'right';
                    }break;
                    case "right":
                    {
                        if(conflict.right) settings.recommend = 'left';
                    }break;
                    default: // Auto
                    {
                        settings.recommend = (elementPos.left < $(window).width() / 2) ? 'right' : 'left';
                    }break;
                }
                if(settings.move == 'vertically')
                {
                    settings.startPoint.x = conflict[settings.recommend+'Point'].x;
                    settings.startPoint.y = settings.startPoint.y = (settings.recommend == 'bottom') ? ($(window).height() / 3) * 2 : ($(window).height() / 3);
                }
                else
                {
                    settings.startPoint.x = (elementPos.left < $(window).width() / 2) ? ($(window).width() / 3) * 2 : ($(window).width() / 3);
                    settings.startPoint.y = conflict[settings.recommend+'Point'].y;
                }

                settings.endPoint.x = conflict[settings.recommend+'Point'].x;
                settings.endPoint.y = conflict[settings.recommend+'Point'].y;
            }break;
        }

        // Setting up distance
        if(typeof(settings.group.distance) == "string")
            settings.group.distance = settings.group.distance.replace(/px$/gi, '');

        if(settings.startPoint.x != settings.endPoint.x && settings.group.distance != 'auto') // horizontal move
        {
            var res = settings.endPoint.x - settings.startPoint.x;
            if(res < 0) // tooltip is moving to left
                settings.startPoint.x = parseInt(settings.endPoint.x) + parseInt(settings.group.distance);
            else // tooltip is moving to right
                settings.startPoint.x = parseInt(settings.endPoint.x) - parseInt(settings.group.distance);
        }

        if(settings.startPoint.y != settings.endPoint.y && settings.group.distance != 'auto') // vertical move
        {
            var res = settings.endPoint.y - settings.startPoint.y;
            if(res < 0) // tooltip is moving to top
                settings.startPoint.y = parseInt(settings.endPoint.y) + parseInt(settings.group.distance);
            else // tooltip is moving to bottom
                settings.startPoint.y = parseInt(settings.endPoint.y) - parseInt(settings.group.distance);
        }


        // Adjusting Arrow
        var arrow = '';

        switch(settings.recommend)
        {
            case "top":
            {
                arrow = _tooltip_generate_arrow("down");
                arrow.style.top = (DIV.offsetHeight-1)+"px";
                arrow.style.left = ((DIV.offsetWidth/2) - (arrow.width/2))+"px";
            }break
            case "bottom":
            {
                arrow = _tooltip_generate_arrow("up");
                arrow.style.top = "-"+arrow.height+"px";
                arrow.style.left = ((DIV.offsetWidth/2) - (arrow.width/2))+"px";
            }break
            case "left":
            {
                arrow = _tooltip_generate_arrow("right");
                arrow.style.top = ((DIV.offsetHeight / 2) - arrow.height / 2)+"px";
                arrow.style.left = (DIV.offsetWidth)+"px";
            }break
            case "right":
            {
                arrow = _tooltip_generate_arrow("left");
                arrow.style.top = ((DIV.offsetHeight / 2) - arrow.height / 2)+"px";
                arrow.style.left = "-"+arrow.width+"px";
            }break
        }
        arrow.id = "tooltip_arrow_"+$(this).attr("id");

        var position = conflict[settings.recommend+'Point'].position;
        switch(position) // by default (if no conflict happends) it will be center, usually it will change when tooltip box is grater than element in size
        {
            case "bottom":
            {
                arrow.style.top = ($(DIV).height() - ($(this).height()/2-arrow.height/2))+"px";
            }break;
            case "top":
            {
                arrow.style.top = ($(this).height()/2-arrow.height/2)+"px";
            }break;
            case "left":
            {
                arrow.style.left = ($(this).width()/2-arrow.width/2)+"px";
            }break;
            case "right":
            {
                arrow.style.left = ($(DIV).width() - ($(this).width()/2 + arrow.width/2))+"px";
            }break;
        }
        // Appending Arrow To Box
        DIV.appendChild(arrow);

        // Moving Box
        opts = $.extend({left: settings.endPoint.x, top: settings.endPoint.y}, {opacity: 1});
        var element = $(this);
        var _this = this;

        this.hideTitle = function()
        {
            opts = $.extend({left: $(DIV).attr("startX"), top: $(DIV).attr("startY")}, {opacity: 0});
            $(DIV).animate(opts, {duration: settings.group.speed, easing: settings.group.hideEasing, complete: function(){if(!isNaN(DIV)) document.body.removeChild(DIV); element.attr("titleActive", "false");}});
            this.onTitleHide.call(this);
            clearInterval(this.onTitleChange);
        }

        this.onTitleShow();
        $(DIV).css({top: settings.startPoint.y, left: settings.startPoint.x}).animate(opts,{
            duration: settings.group.speed,
            easing: settings.group.showEasing,
            complete: function(){
                $(this).attr("startX", settings.startPoint.x).attr("startY", settings.startPoint.y);
                switch(settings.group.ms.toString())
                {
                    case '0': // mouseout
                    {
                        element.bind('mouseout.tooltip', function(){
                            _this.hideTitle();
                        });
                    }break;
                    case '-1':// manual
                    {

                    }break;
                    case '-2':// manual
                    {
                        $(DIV).bind('click.tooltip', function(){
                            _this.hideTitle();
                        });
                    }break;
                    default:
                    {
                        DIV.tooltipTimeout = setTimeout(function(){
                            _this.hideTitle();
                        }, settings.group.ms);
                    }break;
                }

            }
        });
    }

    $.fn.tooltip = function(options){
        return this.each(function(){
            $(this).attr("delay", 'true').bind("mouseout.tooltip", function(){$(this).attr("delay", "false"); clearTimeout(this.delayTimeout);});
            var _this = this;
            var group = (($(this).attr("titleGroup")) ? (groups[$(this).attr("titleGroup")]) ? groups[$(this).attr("titleGroup")] : option : option);
            if(options.forced == true) $.tooltip_proccess.call(_this);
            if(group.delay == -1) return;
            _this.delayTimeout = setTimeout(function(){
                if($(_this).attr("delay") == "true")
                    $.tooltip_proccess.call(_this);
            }, group.delay);
        });
    };
})(jQuery)
0

精彩评论

暂无评论...
验证码 换一张
取 消