16

A few days/weeks ago, some of my sites' twitter widgets stopped pulling through data properly. Turns out Version 2 twitter widget is deprecated, and the new embedded timeline widget is the only way to go, apparently.

https://dev.twitter.com/blog/planning-for-api-v1-retirement

Except this new widget creates an iframe, which prevents any custom styling of the widget from within my own stylesheets - such as setting the font family, font size, colours, etc.

Is there a workaround? From what I'm reading, you can't apply / inject styles into an iframe, and I can't find any API-way of doing it.

I'd also like to limit the widget to just the 3 most recent tweets; not sure if that's possible anymore, and to remove the vertical scroll bar (probably related to limiting the tweets).

Sean
  • 14,359
  • 13
  • 74
  • 124
  • I’m going out on a limb here and say that this is intentional precisely to prevent custom styling of the widget. You may have to create your own widget using the Twitter API to get around this. – Konrad Rudolph Mar 20 '13 at 20:27
  • I can't believe that true - how many thousands of sites have styled the widget to match their look & feel. Now that's gone & you have to have a bland ugly version? I bet a large number just rip it out.... – Sean Mar 20 '13 at 20:41
  • https://stackoverflow.com/a/74012606/7186739 – Billu Oct 10 '22 at 20:02

15 Answers15

16

Instead of targeting individualy the elements with jQuery you can try to inject some inline css style into the head of the page loaded inside the iframe, so new content loaded by the "show more" button will also be changed :

for example to remove avatars pictures :

$("iframe#twitter-widget-0").contents().find('head').append('<style>img.u-photo.avatar{display:none !important;}.header.h-card.p-author{padding-left:0;}</style>');

I use the waituntilexists.js plugin to detect when the content is added to DOM instead of the setTimeout(): https://gist.github.com/buu700/4200601

so we have :

$("iframe#twitter-widget-0").waitUntilExists(function(){
    $("iframe#twitter-widget-0").contents().find('head').append('<style>img.u-photo.avatar{display:none !important;}.header.h-card.p-author{padding-left:0;}</style>');     
});
user2787001
  • 161
  • 1
  • 2
  • nicce. I tried to apply this to the "h-card p-author" showing the name twitterhandle and time but I couldn't get it dissapear. with $("iframe#twitter-widget-0").contents().find('head').append(''); – ramin Jul 12 '14 at 18:58
  • How are you able to access the `.contents()` of the Twitter iframe when the `src` attribute points to their domain? – emersonthis Jul 21 '14 at 20:48
6

The only solution I found with Twitter's Enhanced Timeline is to use javascript to modify the css after the iframe has loaded.

Needed to use window.setTimeout for it. As jamesnotjim mentioned, make sure you put this in the script block below the body tag.

window.setTimeout(function(){
    $(".twitter-timeline").contents().find(".e-entry-title").css("font-family","sans-serif");
    $(".twitter-timeline").contents().find(".tweet").css("font-family","sans-serif");
  }, 1000);
Dominic Tancredi
  • 41,134
  • 7
  • 34
  • 50
  • Where do you drop that to make it work? I've tried that in a script tag inside the head and inside the body, but I'm not seeing any changes. – jamesnotjim Jul 31 '15 at 14:17
  • 1
    My bad. I hadn't loaded jQuery in the head. I ended up putting your code in a script block right below the closing body tag. Works great. Thanks. – jamesnotjim Jul 31 '15 at 14:43
5

Applying styles to the Twitter feed

I would like to build on the answer provided by user2787001. I was finding that even with this approach (using waituntilexists.js on the iframe) the styles were not always being applied. Waiting for the iFrame to load is significant as twitter loads this on the fly. However the iframe then has to load its content; the webpage containing the Twitter feed and should this take longer than expected we will again be trying to apply styles to something that is not there. Ultimately we want to check that the styles have actually been applied on the page within the iframe, only then can we be satisfied that the job is done.

To apply the styling I have referenced a standalone stylesheet containing the appropriate styles, using <link rel="stylesheet"... >. In order to make sure this has been successfully applied I have given it an id (#twitter-widget-styles) which can be checked to confirm the stylesheet has been placed.

Rather than using the waituntilexists.js plugin I have mimicked its behaviour by using window.setInterval. Do not use window.setTimeout with an arbitrary delay. It is quite possible the twitter iframe and its content will take longer to load than anticipated. If the delay is too short styles will fail to apply. If the delay is too long then your users are shown a flash of unstyled content (FOUC)

(note: #twitter-widget-0 is the id twitter uses on its iframe)

//Add twitter widget styling
var $iframeHead;

var twitterStylesTimer = window.setInterval(function(){

    $iframeHead = $("iframe#twitter-widget-0").contents().find('head');

    if( !$('#twitter-widget-styles', $iframeHead).length ){ //If our stylesheet does not exist tey to place it
        $iframeHead.append('<link rel="stylesheet" href="/stylesheets/twitter-widget.css" id="twitter-widget-styles">');
    }else if( $('#twitter-widget-styles', $iframeHead).length ){    //If stylesheet exists then quit timer
        clearInterval(twitterStylesTimer);
    }

}, 200);

Limit number of checks

One small consideration, if the iframe fails to load or the stylesheet never gets applied the timers will run indefinitely. If this is a concern counters can be added to quit the process after a certain number of attempts:

//Add twitter widget styling
var quitStyleCount = 0;
var $iframeHead;

var twitterStylesTimer = window.setInterval(function(){

    $iframeHead = $("iframe#twitter-widget-0").contents().find('head');

    if( !$('#twitter-widget-styles', $iframeHead).length ){ //If our stylesheet does not exist tey to place it
        $iframeHead.append('<link rel="stylesheet" href="/stylesheets/twitter-widget.css" id="twitter-widget-styles">');
    }else if( $('#twitter-widget-styles', $iframeHead).length || ++quitStyleCount > 40){    //If stylesheet exists or we've been trying for too long then quit
        clearInterval(twitterStylesTimer);
    }

}, 200);

Delay times (200ms in the example) and the break counters (40 cycles) can be altered as required.

Cross domain restrictions

As for concerns regarding inserting code into an iframe. If we look at the iframe rendered by twitter it has no src attribute that would pull content from another domain:

<iframe frameborder="0" height="200" id="twitter-widget-0" scrolling="no" allowtransparency="true" class="twitter-timeline twitter-timeline-rendered" allowfullscreen="" style="border: medium none; max-width: 100%; min-width: 180px; width: 520px;" title="Twitter Timeline"></iframe>

I've not investigated this fully but I expect the iframe content is generated on the fly from the twitter script running on the client machine. Therefore interacting with it does not breech any cross domain restrictions.

Limiting number of tweets

To limit the number of tweets use the data-tweet-limit="x" attribute on the anchor tag used on the embed code

<a class="twitter-timeline" data-tweet-limit="3" href="https://twitter.com/xxxxxxxxxxxx" data-widget-id="xxxxxxxxxxxxx">Tweets by xxxxxxxxxx</a>...

This is discussed in the twitter documentation:

Tweet limit: To fix the size of a timeline to a preset number of Tweets, use the data-tweet-limit="5" attribute with any value between 1 and 20 Tweets. The timeline will render the specified number of Tweets from the timeline, expanding the height of the widget to display all Tweets without scrolling. Since the widget is of a fixed size, it will not poll for updates when using this option.

Remove vertical scroll bars

I'd need to see your code to give a definite answer. There is an attribute that may solve your problem, again discussed in the twitter documentation, under the section "Chrome":

data-chrome="noscrollbar"

noscrollbar: Crops and hides the main timeline scrollbar, if visible. Please consider that hiding standard user interface components can affect the accessibility of your website.

CSS styling may also give control over scrollbars with options such as overflow: hidden.

a gorsky
  • 309
  • 3
  • 5
  • I love you! Thanks for this, this should be the correct answer as it's the only one that really constantly works. – Jeff Sep 29 '15 at 09:19
4

You can import twitter-widget.js javascript in your own project, then modify some styling from within this .js file.

After, you invoke it instead of invoking the twitter's site library //your.ownsite.web/widgets.js. It is actually working, but no guaranties for the future.

    <a class="twitter-timeline" href="https://twitter.com/twitterapi" data-widget-id="YOUR-WIDGET-ID-HERE">Tweets by @twitterapi</a>

<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

In the .js, look for this block of code :

setupSandbox: function (a) {
                var b = a.doc,
                    c = b.createElement("base"),
                    d = b.createElement("style"),
                    f = b.getElementsByTagName("head")[0],
                    g = "body{display:none} .timeline{border:1px solid #CCCCCC} .timeline-header{background-color:#F3F3F3;padding:8px 14px;-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;} .timeline-header h1.summary{background-color:#F3F3F3; border-bottom:1px solid #EBEBEB; -moz-border-radius:5px 5px 0 0; -webkit-border-radius:5px 5px 0 0; border-radius:5px 5px 0 0; font-size:14px; font-weight:400; line-height:18px; margin:0; padding:0;};",
                    h = this,
                    i;
Milche Patern
  • 19,632
  • 6
  • 35
  • 52
4

I can at least help with limiting the tweets and removing the scroll bar.

From the documentation:

Tweet limit: To fix the size of a timeline to a preset number of Tweets, use the data-tweet-limit="5" attribute with any value between 1 and 20 Tweets.

And

Chrome: Control the widget layout and chrome by using the data-chrome="nofooter transparent" attribute on the embed code. Use a space-separated set of the following options: noheader, nofooter, noscrollbar, transparent.

Still looking at the styling.

robert.andre.brink
  • 263
  • 1
  • 3
  • 9
2

Go to this site and download this plugin, then you can style in anyway you chose Jason Mayes

Lemuel Botha
  • 659
  • 8
  • 22
1

See "client side options" here. But basically, you can slap the whole thing in a styled div, remove the header & footer & make the background transparent. I'm personally still searching for a way to limit the number of tweets & get rid of the user icon.

Here's our code (Drupal block): ok, I can't get the code to show nicely.

t-readyroc
  • 11
  • 1
1

This is working for me

function twitterfix() {

    if(typeof $("#twitter-widget-0").contents().find(".load-more").html() == 'undefined') {
        setTimeout(twitterfix, 500);
        }
    else {
        var head = $("#twitter-widget-0").contents().find("head");
        head.append('<link type="text/css" rel="stylesheet" href="wp-content/themes/mywordpresstheme/style.css">');
        head.append('<style>.h-entry.tweet.with-expansion.customisable-border {border-bottom: 1px solid #EFEEEE;}</style>');
        }
}

$(document).ready(function () {

    twitterfix();

});

wiki.workassis.com

Bikesh M
  • 8,163
  • 6
  • 40
  • 52
1

I've found that you can use document ready without the settimeout, provided you wrap the widget in a container. This should trigger not only on page load, but on any dynamic content changes in the timeline itself after page load.

jQuery(document).ready( function() {
   jQuery('.twitter-block').on('DOMSubtreeModified propertychange',"#twitter-widget-0", function() {
     //your element changes here.
     //Hide media items
     jQuery(".twitter-timeline").contents().find(".timeline-Tweet-media").css("display", "none");
     //Resize iframe when new content is posted.
     jQuery(".twitter-block").css("height", "100%");
   });
});

Otherwise, I agree with a-gorsky regarding adding a stylesheet into the iframe rather than making the style changes to every element.

user3903555
  • 106
  • 1
  • 3
0

In the Microsoft MVC world there are helpers in the Microsoft.Web.Helpers library, specifically using:

@Twitter.Profile(...

The above is just a wrapper around the V2 widget, but indicates there is a high usage of that particular widget.

I've looked into your question for a while now (in fact when the deprecation message started appearing) and I have come to the following conclusions:

  1. The widget will not be deprecated due to its wide use
  2. If it is deprecated a far richer timeline widget will be available
  3. Failing this it will be the case of using the API and writing our own widgets, which will be a step back for Twitter
ozzy
  • 999
  • 12
  • 12
0

This is what I did. If you limit the number of posts, it automatically removes the slider.

<a  class="twitter-timeline"  href="https://twitter.com/YOUR_ACCOUNT_NAME"  data-widget-id="YOUR_ID_HERE" data-tweet-limit="4">Tweets by @YOUR_ACCOUNT_NAME</a>
Garrett Hyde
  • 5,409
  • 8
  • 49
  • 55
0

Simple enough to set the number of Tweets:

Tweet limit: To fix the size of a timeline to a preset number of Tweets, use the data-tweet-limit="5" attribute with any value between 1 and 20 Tweets. The timeline will render the specified number of Tweets from the timeline, expanding the height of the widget to display all Tweets without scrolling. Since the widget is of a fixed size, it will not poll for updates when using this option.

Not sure how to remove the user icon though.

Mark
  • 1
0

The timeline inserts an iframe into the page, so why not just get the contents of the iframe and do whatever with it?

Here is how its done with jquery for example:

$($('#IFRAME_ID').contents().find('body'))

You now have the complete twitter feed as a DOM tree, do whatever you want.

YemSalat
  • 19,986
  • 13
  • 44
  • 51
0

If you take a look at widgets.js and look for this line:

e.appendStyleSheet(twttr.widgets.config.assetUrl() + "/" + r("embed/timeline.css"))).then(p.bind(function() {

You can copy timeline.css and modify both files however you like.

davidcondrey
  • 34,416
  • 17
  • 114
  • 136
0

Everything about hide things in twitter timeline Use data-chrome="noheader, nofooter, noborders"

<a class="twitter-timeline" 
             href="https://twitter.com/..."
             data-height="400"
             data-chrome="noheader, nofooter, noborders"
             data-tweet-limit="3"
             data-border-color="#bdbdbd"
             >Tweets Timeline</a>
    <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Guide: https://developer.twitter.com/en/docs/twitter-for-websites/timelines/guides/parameter-reference

Billu
  • 2,733
  • 26
  • 47